折叠可变参数模板检查是否存在成员函数

时间:2015-12-01 20:32:53

标签: c++ variadic-templates sfinae

我正在使用SFINAE惯用法检查某个类型是否包含具有特定签名的方法(function_name())。我实现的解决方案适用于单一类型,但我想让它适用于多种类型(通过可变参数模板)。

template <typename... Other>
class has_foo {
   public:
    static constexpr bool value = has_foo<Other...>::value;
};

template <typename U, typename ...Other> // Error here
class has_foo {
   public:
    static constexpr bool value = has_foo<U>::value && has_foo<Other...>::value;
};

template <typename U>
class has_foo {
   private:
    template <typename T, T>
    struct helper;
    template <typename T>
    static std::uint8_t check(helper<int (*)(size_t), &T::function_name>*);
    template <typename T>
    static std::uint16_t check(...);

   public:
    static constexpr bool value = sizeof(check<U>(0)) == sizeof(std::uint8_t);
};

template <>
class has_foo<void> {
   public:
    static constexpr bool value = false;
};

我收到以下错误:too many template parameters in template redeclaration。我在这里做错了什么?

2 个答案:

答案 0 :(得分:0)

template <typename U, typename ...Other>
class has_foo {
public:
    static constexpr bool value = has_foo<U>::value && has_foo<Other...>::value;
};

// partial template specialization
template <typename... Other>
class has_foo<void, Other...>{
public:
    static constexpr bool value = has_foo<void,Other...>::value;
};

// partial template specialization
template <typename U>
class has_foo<U,void> {
private:
    template <typename T, T>
    struct helper;
    template <typename T>
    static std::uint8_t check(helper<int (*)(size_t), &T::function_name>*);
    template <typename T>
    static std::uint16_t check(...);

public:
    static constexpr bool value = sizeof(check<U>(0)) == sizeof(std::uint8_t);
};

// partial template specialization
template <>
class has_foo<void> {
public:
    static constexpr bool value = false;
};

答案 1 :(得分:0)

即使我无法测试它不是mvce,也许下面的代码可以正常使用。

template<typename... Args>
class has_foo { };

template <typename U, typename ...Other>
class has_foo<U, Other...>: public has_foo<Other...> {
    template <typename t, t>
    struct helper;

    template <typename t>
    static std::uint8_t check(helper<int (*)(size_t), &t::function_name>*);

    template <typename t>
    static std::uint16_t check(...);

public:
    static constexpr bool value = (sizeof(check<U>(0)) == sizeof(std::uint8_t)) && has_foo<Other...>::value;
};

template <>
class has_foo<> {
public:
    static constexpr bool value = true;
};

template <>
class has_foo<void> {
public:
    static constexpr bool value = false;
};

这里还有一个简化的修订版本:

#include <iostream>

template<typename... Args>
class has_foo { };

template <typename U, typename ...Other>
class has_foo<U, Other...>: public has_foo<Other...> {
public:
    static constexpr bool value = true && has_foo<Other...>::value;
};

template <>
class has_foo<> {
public:
    static constexpr bool value = true;
};

template <>
class has_foo<void> {
public:
    static constexpr bool value = false;
};

int main() {
    std::cout << has_foo<int, double, char>::value << std::endl;
    std::cout << has_foo<int, double, void>::value << std::endl;
    std::cout << has_foo<>::value << std::endl;
}

基本思想是定义一个可变结构,然后专门用于所有允许它工作的必要情况,而不是void看起来对你感兴趣的情况。

目前,它为示例中的最后一个案例返回true,我不知道如何处理这种情况,因为你没有给出任何建议。无论如何,从上面的例子开始,您可以根据您的要求轻松修改它。