xin*_*aiz 12 c++ templates sfinae c++03 c++17
这个问题的灵感来自于这个答案.我想知道在给定标准中简化它的最佳方法是什么.一个我知道并且个人使用/仍在使用,因为C++ 14是宏REQUIRES(x):
定义:
template<long N>
struct requires_enum
{
enum class type
{
none,
all
};
};
#define REQUIRES(...) requires_enum<__LINE__>::type = \
requires_enum<__LINE__>::type::none, \
bool PrivateBool = true, \
typename std::enable_if<PrivateBool && (__VA_ARGS__), int>::type = 0
Run Code Online (Sandbox Code Playgroud)
即使对于非模板化函数调用也使用:
template<REQUIRES(sizeof(int)==4)>
int fun() {return 0;}
int main()
{
fun(); //only if sizeof(int)==4
}
Run Code Online (Sandbox Code Playgroud)
REQUIRES我使用的原文来自这篇文章.
还有什么好的技巧?
SFINAE的一些例子需要一些或很长时间才能理解读者刚开始使用SFINAE的冒险:
Pre-C++ 11 SFINAE示例(来源):
template <typename T>
struct has_typedef_foobar {
// Types "yes" and "no" are guaranteed to have different sizes,
// specifically sizeof(yes) == 1 and sizeof(no) == 2.
typedef char yes[1];
typedef char no[2];
template <typename C>
static yes& test(typename C::foobar*);
template <typename>
static no& test(...);
// If the "sizeof" of the result of calling test<T>(nullptr) is equal to sizeof(yes),
// the first overload worked and T has a nested type named foobar.
static const bool value = sizeof(test<T>(nullptr)) == sizeof(yes);
};
Run Code Online (Sandbox Code Playgroud)
如果你正在使用C++ 11(示例代码包含std::enable_if,所以我猜这是这种情况)或连续修订,我会static_assert在这种情况下使用a :
int fun() {
static_assert(sizeof(int)==4, "!");
return 0;
}
int main() {
fun();
}
Run Code Online (Sandbox Code Playgroud)
您没有一套可以从中选择工作的功能.
正如我曾经说过的那样,更多的是替换失败总是错误,而替换失败不是错误.
你想要的是一个编译时触发器和一个static_assert温和的错误消息.
当然,它也比复杂的sfinae表达更容易阅读!!
如果要在两个函数之间进行选择而不想使用模板机制或宏,请不要忘记重载是语言的一部分(前C++ 11工作示例):
#include <iostream>
template<bool> struct tag {};
int fun(tag<true>) { return 0; }
int fun(tag<false>) { return 1; }
int fun() { return fun(tag<sizeof(int) == 4>()); }
int main() {
std::cout << fun() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
这可以很容易地扩展到函数超过两个的情况:
#include <iostream>
template<int> struct tag {};
int fun(tag<0>) { return 0; }
int fun(tag<1>) { return 1; }
int fun(tag<2>) { return 2; }
int fun(bool b) {
if(b) { return fun(tag<0>()); }
else { return fun(tag<(sizeof(int) == 4) ? 1 : 2>());
}
int main() {
std::cout << fun(false) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
您可以将这些函数放在匿名命名空间中,然后使用它们.
当然,还需要注意的是,在C++之前的版本11中,我们被授权为自己编写enable_if和所有其他内容type_traits.
举个例子:
template<bool b, typename = void>
struct enable_if { };
template<typename T>
struct enable_if<true, T> { typedef T type; };
Run Code Online (Sandbox Code Playgroud)