如何简化复杂的SFINAE语法,在前C ++ 11,C ++ 11,14和17? [英] How to simplify complicated SFINAE syntax, in pre-C++11, C++11, 14 and 17?

查看:152
本文介绍了如何简化复杂的SFINAE语法,在前C ++ 11,C ++ 11,14和17?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题的灵感来自这个答案。我不知道什么是/是在给定的标准中简化它的最好的方法。我知道并亲自使用/仍然使用,因为C ++ 14是宏 REQUIRES(x)



定义:

 模板< long N> 
struct requires_enum
{
枚举类型类型
{
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

  template< REQUIRES(sizeof(int)== 4)> 
int fun(){return 0;}

int main()
{
fun(); // only if sizeof(int)== 4
}

$ c> REQUIRES 我使用的是来自此









SFINAE的一些例子需要一些或者很长的时间来理解刚刚开始使用SFINAE的冒险:



Pre-C ++ 11 SFINAE示例():

  template< typename T> 
struct has_typedef_foobar {
//类型yes和no保证有不同的大小,
//具体是sizeof(yes)== 1和sizeof 。
typedef char yes [1];
typedef char no [2];

template< typename C>
static是& test(typename C :: foobar *);

template< typename>
static no&测试(...);

//如果调用test< T>(nullptr)的结果的sizeof等于sizeof(是),则
//第一重载工作,T具有嵌套类型命名为foobar。
static const bool value = sizeof(test< T>(nullptr))== sizeof(yes);
};


解决方案

如果你使用C ++ 11示例代码包含 std :: enable_if ,所以我想是这种情况)或连续修订,我会使用 static_assert 在这种情况下:

  int fun(){
static_assert(sizeof(int)== 4, !);
return 0;
}

int main(){
fun();
}

您没有一组

正如我曾经说过的,这是一个替换失败总是一个错误比一个替换失败不是一个错误

你想要的是一个编译时触发器和一个 static_assert 它带有温柔的错误信息。



当然,它也比复杂的sfinae表达式更容易阅读!!






如果要在两个函数之间进行选择,并且不想使用模板机制或宏,请不要忘记重载是语言的一部分(pre-C ++ 11工作示例):

  #include< iostream> 

模板< 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;
}

这可以很容易地扩展到函数超过两个的情况:

  #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;
}

您可以将这些函数放在匿名命名空间中, / p>




当然,请注意,在前C ++ 11中,我们有权写 enable_if 以及来自 type_traits 的所有其他内容。

例如:

 模板< bool b,typename = void> 
struct enable_if {};

template< typename T>
struct enable_if< true,T> {typedef T type; };


This question was inspired by this answer. I wonder what are/were the best ways to simplify it in given standards. One I know and personally used/still use since C++14 is macro REQUIRES(x):

With definition:

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

And use if even for non-templated function calls:

template<REQUIRES(sizeof(int)==4)>
int fun() {return 0;}

int main()
{ 
    fun(); //only if sizeof(int)==4
}

The original REQUIRES I use is from this post.

What are the other good techniques?


Some examples of SFINAE that require some, or long time to understand for reader that just started the adventure with SFINAE:

Pre-C++11 SFINAE example (Source):

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);
};

解决方案

If you are working with C++11 (the example code contains std::enable_if, so I guess this is the case) or a successive revision, I would use a static_assert in this case:

int fun() {
    static_assert(sizeof(int)==4, "!");
    return 0;
}

int main() {
    fun();
}

You don't have a set of functions from which to pick a working one up.
As I've been said once, this is more a substitution failure is always an error than a substitution failure is not an error.
What you want is a compile-time trigger and a static_assert does it with gentle error messages.

Of course, it's also far easier to read than a complicated sfinae expression too!!


If you want to choose between two functions and you don't want to use template machinery or macros, do not forget that overloading is part of the language (pre-C++11 working example):

#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;
}

This can be easily extended to the cases where the functions are more than two:

#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;
}

You can put those functions in an anonymous namespace and get away with them.


Of course, note also that in pre-C++11 we were authorized to write enable_if and all the other things from type_traits for ourselves.
As an example:

template<bool b, typename = void>
struct enable_if { };

template<typename T>
struct enable_if<true, T> { typedef T type; };

这篇关于如何简化复杂的SFINAE语法,在前C ++ 11,C ++ 11,14和17?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆