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

斯科特·泰格(Scott Tiger)

我试图在一个可变参数派生类的所有基类上“迭代”,并调用一个名为“ 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> {
         ^
皮特·斯科特尼克(Piotr Skotnicki)

使用由您的类型特征组成的标记分派:

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

SFINAE和可变参数模板类

decltype()可变参数模板基类

C ++创建具有可变参数模板方法的接口

具有递归继承并使用声明的可变参数模板

如何检查所有可变参数模板参数是否都具有特殊功能?

是否可以从可变参数模板调用多个基类构造函数?

可变参数模板和SFINAE

具有模板函数名称的可变参数模板

如何扩展对可变参数模板基类的调用?

可变参数模板类的可变参数模板

具有可变参数模板参数的函数指针

具有左值和右值的可变参数模板类构造函数

当可变参数模板类从模板参数继承时,在调用基类型的方法时扩展参数包

是否可以构建具有不同类型的可变参数模板?

具有依赖类型的c ++ 11可变参数函数模板是否不明确?

在C ++中可变参数模板中是否有对函数参数实施类型限制的好方法?

使用可变参数类模板的模板参数调用可变参数函数模板?

具有const引用的可变参数模板

具有双打的C ++可变参数模板

具有可变参数模板的成员函数指针

具有元组的C ++可变参数模板

如何具有类型和大小的可变参数模板?

使用专门的可变参数模板类的声明

具有右值引用,而不是使用可变参数模板转发引用

使用带有可变参数模板类的boost mpl lambda

使用概念或SFINAE检查类是否具有带有std :: array参数的模板化成员函数

从具有可变参数的模板类继承

从可变参数模板构造类

如何扩展可变参数模板类