检查模板功能是否存在

时间:2017-08-06 21:17:44

标签: c++ templates c++14 sfinae template-specialization

如何检查是否存在这样的模板函数:检查reader struct是否具有read算术值

struct reader {
    template<typename T>
    std::enable_if_t<std::is_arithmetic<T>::value, T> read() {
        return {};
    }
};

我使用这样的检查器:

template <typename T>
struct test_read {
    static constexpr auto value = std::is_convertible<decltype(std::declval<T>().read<int>()),int>::value;      
};

但是编译器抱怨道:

error: wrong number of template arguments (1, should be 2)
 static constexpr auto value = std::is_convertible<decltype(std::declval<T>().read<int>()),int>::value;

请就此向我提出建议。

谢谢。

更新:这是我在讨论后得到的最终版本,我希望每个人都会发现它对您的代码有帮助

struct not_reader {

};


struct reader {
    template<typename T>
    std::enable_if_t<std::is_arithmetic<T>::value, T> read() {
        return {};
    }
};


template<class T, class Elem>
struct has_read {
private:
    template<class C, typename=void>
    struct test_read : std::false_type {
    };
    template<class C>
    struct test_read<C, typename std::enable_if<std::is_convertible<decltype(std::declval<C>().template read<Elem>()), Elem>::value>::type>
            : std::true_type {
    };
public:
    using type = typename test_read<T>::type;
    static constexpr bool value = test_read<T>::value;
};


static_assert(has_read<reader, int>::value, "reader should have int read()");
static_assert(!has_read<not_reader, int>::value, "not_reader should not have int read()");

2 个答案:

答案 0 :(得分:4)

您在template

之前忘记了read()
static constexpr auto value
    = std::is_convertible<
         decltype(std::declval<T>().template read<int>()),int>::value;  
// .................................#########    

但我不认为您的代码可以检查“reader struct是否具有read算术值”:尝试使用类型test_read调用int并且您应该获得编译错误。

以下是替代解决方案的示例

#include <type_traits>

struct reader
 {
   template<typename T>
   std::enable_if_t<std::is_arithmetic<T>::value, T> read()
    { return {}; }
 };

template <typename, typename = void>
struct readTypeRet
 { using type = void; };

template <typename T>
struct readTypeRet<T, decltype(std::declval<T>().template read<int>(), void())>
 { using type = decltype(std::declval<T>().template read<int>()); };

template <typename T>
struct test_read
    : public std::is_convertible<typename readTypeRet<T>::type, int>
 { };

int main ()
 {
   static_assert(test_read<reader>::value == true, "!");
   static_assert(test_read<int>::value == false,   "!");
 }

答案 1 :(得分:1)

以更清晰的方式简要地重述您的问题:

  • 如果T满足T,您的某些功能会返回is_arithmetic,否则会返回void
  • 您想断言用int调用此函数会返回一个可转换为int的类型

我认为修复代码的最短路径是利用Supervisor(C ++ 11/14,在C ++中使用std::invoke_result_t 17):

template<class T>
struct test_read {
static constexpr auto value = std::is_convertible<
    typename std::result_of<decltype(&T::template read<int>)(T)>::type, int
    >::value;    
};

std::result_of

关于此解决方案的一些注意事项:

  • 指定read T reader成员函数时,我们需要使用Live Demo关键字通知编译器名称reader是一个模板。
  • 使用result_of需要F(Args)的类似函数的语法,因此我们将reader::read的类型作为F部分,然后传递{{ 1}}作为reader部分
    • 我们必须将ArgsT的实例传递给reader),因为它是一个成员函数(而不是read或免费),并且成员函数隐含地采用引用他们被调用的类的实例。