SFINAE在返回类型中工作,但不作为模板参数
SFINAE working in return type but not as template parameter
我已经使用了SFINAE习语很多次,我习惯了把我的std::enable_if<>
放在模板参数中,而不是返回类型中。然而,我遇到了一些微不足道的情况,它没有工作,我不知道为什么。首先,这是我的main:
int main()
{
foo(5);
foo(3.4);
}
下面是触发错误的foo
的实现:
template<typename T,
typename = typename std::enable_if<std::is_integral<T>::value>::type>
auto foo(T)
-> void
{
std::cout << "I'm an integer!n";
}
template<typename T,
typename = typename std::enable_if<std::is_floating_point<T>::value>::type>
auto foo(T)
-> void
{
std::cout << "I'm a floating point number!n";
}
这里有一段类似的代码,可以正常工作:
template<typename T>
auto foo(T)
-> typename std::enable_if<std::is_integral<T>::value>::type
{
std::cout << "I'm an integrer!n";
}
template<typename T>
auto foo(T)
-> typename std::enable_if<std::is_floating_point<T>::value>::type
{
std::cout << "I'm a floating point number!n";
}
我的问题是:为什么foo
的第一个实现触发错误,而第二个不触发它?
main.cpp:14:6: error: redefinition of 'template<class T, class> void foo(T)' auto foo(T) ^ main.cpp:6:6: note: 'template<class T, class> void foo(T)' previously declared here auto foo(T) ^ main.cpp: In function 'int main()': main.cpp:23:12: error: no matching function for call to 'foo(double)' foo(3.4); ^ main.cpp:6:6: note: candidate: template<class T, class> void foo(T) auto foo(T) ^ main.cpp:6:6: note: template argument deduction/substitution failed: main.cpp:5:10: error: no type named 'type' in 'struct std::enable_if<false, void>' typename = typename std::enable_if<std::is_integral<T>::value>::type> ^
编辑:
工作代码和故障代码。
您应该看看14.5.6.1 Function template overloading
(c++ 11标准),其中定义了函数模板等效性。简而言之,不考虑默认模板参数,因此在第一种情况下,您将定义两次相同的函数模板。在第二种情况下,表达式引用返回类型中使用的模板参数(再次参见14.5.6.1/4)。由于该表达式是签名的一部分,因此您将获得两个不同的函数模板声明,因此SFINAE有机会工作。
模板中的值:
template<typename T,
typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
auto foo(T)
-> void
{
std::cout << "I'm an integer!n";
}
template<typename T,
typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0>
auto foo(T)
-> void
{
std::cout << "I'm a floating point number!n";
}
模板的= ...
只是给出了一个默认参数。这不是实际签名的一部分,看起来像
template<typename T, typename>
auto foo(T a);
用于和函数。
根据您的需要,这个问题最通用的解决方案是使用标签调度。
struct integral_tag { typedef integral_tag category; };
struct floating_tag { typedef floating_tag category; };
template <typename T> struct foo_tag
: std::conditional<std::is_integral<T>::value, integral_tag,
typename std::conditional<std::is_floating_point<T>::value, floating_tag,
std::false_type>::type>::type {};
template<typename T>
T foo_impl(T a, integral_tag) { return a; }
template<typename T>
T foo_impl(T a, floating_tag) { return a; }
template <typename T>
T foo(T a)
{
static_assert(!std::is_base_of<std::false_type, foo_tag<T> >::value,
"T must be either floating point or integral");
return foo_impl(a, typename foo_tag<T>::category{});
}
struct bigint {};
template<> struct foo_tag<bigint> : integral_tag {};
int main()
{
//foo("x"); // produces a nice error message
foo(1);
foo(1.5);
foo(bigint{});
}
相关文章:
- 我正在开发服务器,ip作为参数传递不起作用
- 如何在不使用指针的情况下将派生类的对象作为参数传递给基类中的函数?
- 是否可以在不填充自己的参数的情况下将模板函数作为参数传递?
- C++线程找不到函数作为参数(链接器)
- 有没有办法计算函数内arry的长度而不是作为参数传入?
- 可变参数函数模板不能很好地使用 std::function 作为参数
- 在C++ Lambda 表达式中,为什么人们更喜欢按值捕获而不是作为参数传递?
- 在将匿名对象作为参数传递时,不会调用任何构造函数
- 交换不使用函数作为参数
- C++ _beginthread不能将字符串作为参数传递
- 我的代码在作为参数传入 .begin() 时不起作用,但在我将 .begin() 转换为迭代器后工作
- 是否可以在不扩展初始宏的情况下将一个宏作为参数提供给另一个宏?
- 构造函数不会将使用 new 初始化的数组作为参数
- 如果作为参数传递的函子不带参数,则启用模板
- 为什么构造函数C++接受不正确的类型作为参数?
- 为什么C++可变参数模板不接受 iostream 值作为参数?
- C++:将引用作为参数传递,但该函数不接受引用作为参数
- 为什么不能将std :: async用于接收对抽象类作为参数的函数
- 作为参数的空初始值设定项列表不调用默认构造函数
- 不能将类实例化为 LHS 值,并将限定枚举作为参数 (C++ VS2015)