我已经使用了很多次SFINAE习惯用法,我习惯将std::enable_if<>
放在模板参数中而不是返回类型中。但是,我遇到了一些不起作用的琐碎案例,我不知道为什么。首先,这是我的主要内容:
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> ^
编辑:
答案 0 :(得分:33)
您应该查看14.5.6.1 Function template overloading
(C ++ 11标准),其中定义了函数模板等效性。简而言之,不考虑默认模板参数,因此在第一种情况下,您将定义两次相同的函数模板。在第二种情况下,您有表达式引用返回类型中使用的模板参数(再次参见14.5.6.1/4)。由于此表达式是签名的一部分,因此您将获得两个不同的函数模板声明,因此SFINAE有机会工作。
答案 1 :(得分:9)
模板的= ...
只提供默认参数。这不是实际签名的一部分,看起来像
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{});
}
答案 2 :(得分:8)
模板中的值有效:
var query = {job:"developer",sick:1};
User.count(query, function(err, count) {
if(err) console.log(err);
console.log(count);
});