我在一个项目中大量使用 SFINAE 函数,但不确定以下两种方法(样式除外)之间是否存在任何差异:
#include <cstdlib>
#include <type_traits>
#include <iostream>
template <class T, class = std::enable_if_t<std::is_same_v<T, int>>>
void foo()
{
std::cout << "method 1" << std::endl;
}
template <class T, std::enable_if_t<std::is_same_v<T, double>>* = 0>
void foo()
{
std::cout << "method 2" << std::endl;
}
int main()
{
foo<int>();
foo<double>();
std::cout << "Done...";
std::getchar();
return EXIT_SUCCESS;
}
Run Code Online (Sandbox Code Playgroud)
程序输出如预期:
method 1
method 2
Done...
Run Code Online (Sandbox Code Playgroud)
我已经看到方法 2 在 stackoverflow 中使用得更频繁,但我更喜欢方法 1。
这两种方法有什么不同吗?
为什么这段代码有效:
template<
typename T,
std::enable_if_t<std::is_same<T, int>::value, T>* = nullptr>
void Add(T) {}
template<
typename T,
std::enable_if_t<!std::is_same<T, int>::value, T>* = nullptr>
void Add(T) {}
Run Code Online (Sandbox Code Playgroud)
并且可以正确区分这两个调用:
Add(1);
Add(1.0);
Run Code Online (Sandbox Code Playgroud)
而以下代码如果编译导致重新定义Add()错误?
template<
typename T,
typename = typename std::enable_if<std::is_same<T, int>::value, T>::type>
void Add(T) {}
template<
typename T,
typename = typename std::enable_if<!std::is_same<T, int>::value, T>::type>
void Add(T) {}
Run Code Online (Sandbox Code Playgroud)
所以如果模板参数是类型,那么我们就重新定义了函数,如果它是非类型的,那么一切都好.
据我所知,SFINAE意味着替换失败不会导致编译错误,只是从可能的重载列表中删除原型.
我不明白:为什么这个SFINAE:
template <bool C, typename T = void> struct enable_if{};
template <typename T> struct enable_if<true, T> { typedef T type; };
Run Code Online (Sandbox Code Playgroud)
但这不是吗?
template <bool C> struct assert;
template <> struct assert<true>{};
Run Code Online (Sandbox Code Playgroud)
根据我的理解,这里的基本逻辑是相同的.这个问题来自对这个答案的评论.
在cppreference的语言参考中std::enable_if包括以下注释
笔记
一个常见的错误是声明两个仅在默认模板参数上有所不同的函数模板.这是非法的,因为默认模板参数不是函数模板签名的一部分,并且声明具有相同签名的两个不同函数模板是非法的.
在下面的示例中的模板函数中,在我看来,这种情况发生.即,两个模板函数onlyForDerivedObjects(...)似乎(对我来说)仅由它们的默认模板参数不同.我意识到我在这里遗漏了一些东西,希望有人可以向我解释这一点,或者指出我可能会为自己找到顿悟的方向.
typename std::enable_if ...当我认为它产生两个模板函数的情况时,我在下面的模板函数中错误分类了部分,这两个模板函数的区别仅在于它们的默认模板参数?基础和派生类:
class BaseA
{
public:
int getInt() const { return 21; };
};
class DerivedA : public BaseA {};
class BaseB
{
public:
int getAnotherInt() const { return 33; };
};
class DerivedB : public BaseB {};
Run Code Online (Sandbox Code Playgroud)
具有以下模板功能
/* template functions that, seemingly, only differ in their
default template arguments? */
template< class T,
typename std::enable_if<std::is_base_of<BaseA, …Run Code Online (Sandbox Code Playgroud)