ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

c – 使用sfinae来检测可变参数模板的基类是否具有特定方法

2019-07-27 16:05:29  阅读:190  来源: 互联网

标签:c c14 variadic-templates sfinae


我试图“迭代”一个可变参数派生类的所有基类,并调用一个名为“stream”的方法(如果它存在).

要检查方法是否存在,我使用sfinae,它可以工作(参见注释掉的代码).但是当我将它与可变参数模板“迭代”结合起来如果不起作用时,你的错误有点看起来像sfinae部分突然工作不像预期的那样,当在可变参数魔法里面.

帮助赞赏.我用的是gcc 5.3.0.

#include <type_traits>
#include <iostream>

namespace detail{
  template<class> struct sfinae_true : std::true_type{};

  template<class T, class A0, class A1> static auto test_stream( int) -> sfinae_true<decltype(
          std::declval<T>().stream(std::declval<A0>(), std::declval<A1>()))>;
  template<class, class A0, class A1> static auto test_stream(long) -> std::false_type;
}

template<class T, class A0, class A1> struct has_stream : decltype(detail::test_stream<T, A0, A1>(0)){};

struct X{ void stream(int, bool){} };
struct A{ void stream(int, bool){} };
struct Y{};

template <typename ... T> class Z : public T ... {
    public:
    void ff() {
        std::initializer_list<bool> {
            ( has_stream<T,int,bool>() ? (T::stream(0, 0) , true) : false) ...
        };
    }
};

int main(){

    Z<X,A> a;
    Z<X,A,Y> b;

/* this works as expected.
    // this runs
    if (has_stream<X, int, bool>()) {
        std::cout << "has int, bool" << std::endl;
    }
    // and this doesn't
    if (has_stream<Y, int, long>()) {
        std::cout << "has int long" << std::endl;
    }
*/

    a.ff(); // no error
    b.ff(); // error

}


$g++ --std=c++14 -O0 2.cpp                                                                                                                                                     
2.cpp: In instantiation of ‘void Z<T>::ff() [with T = X, A, Y]’:
2.cpp:41:10:   required from here
2.cpp:22:52: error: ‘stream’ is not a member of ‘Y’
             ( has_stream<T,int,bool>() ? (T::stream(0, 0) , true) : false) ...
                                                    ^
2.cpp:21:9: error: no matching function for call to ‘std::initializer_list<bool>::initializer_list(<brace-enclosed initializer list>)’
         std::initializer_list<bool> {
         ^

解决方法:

使用由您的类型特征组成的标签调度:

void ff()
{
    std::initializer_list<int> {
        (call<T>(has_stream<T,int,bool>{}), 0)...
    };
}   

template <typename U>
void call(std::true_type)
{
    U::stream(0, 0);
}

template <typename U>
void call(std::false_type) {}

或使用表达式SFINAE:

void ff()
{
    std::initializer_list<int> {
        (call<T>(0), 0)...
    };
}   

template <typename U>
auto call(int) -> decltype(U::stream(0, 0), void())
{
    U::stream(0, 0);
}

template <typename U>
void call(char) {}

标签:c,c14,variadic-templates,sfinae
来源: https://codeday.me/bug/20190727/1555558.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有