通过模板参数将方法添加到类

时间:2013-11-29 15:52:15

标签: c++ sfinae enable-if

我想在类unsing的enable_if中有一个模板参数特定的函数。它的名称保持不变,参数类型不同(虽然这不应该是相关的,因为只有一个被初始化)。

enum class MyCases {
    CASE1,
    CASE2
};

template<enum MyCases case>
class MyClass
{
    template<typename = typename std::enable_if<case == MyCases::CASE1>::type>
    void myFunction(ParameterTypeA a) {
        ...
    }

    template<typename = typename std::enable_if<case == MyCases::CASE2>::type>
    void myFunction(ParameterTypeB b) {
        ...
    }
};

我现在得到一个错误,说编译器希望使用CASE2实例化第一个函数,使用CASE1实例化第二个函数,尽管我认为替换失败不应该导致错误(SFINAE)。我究竟做错了什么?谢谢你的帮助!

error: no type named ‘type’ in ‘struct std::enable_if<false, void>’

1 个答案:

答案 0 :(得分:3)

这是一个解决方案。向下滚动以查看我的思考过程。

#include <type_traits>
#include <iostream>

struct ParameterTypeA {};
struct ParameterTypeB {};

enum class MyCases {
    CASE1,
    CASE2
};

template<enum MyCases U>
class MyClass
{
public:
    MyClass() { }
    ~MyClass() { }

    template<enum MyCases T = U>
    void myFunction(ParameterTypeA a, typename std::enable_if<T == MyCases::CASE1, void>::type* = nullptr) {
        std::cout << "A" << std::endl;
    }

    template<enum MyCases T = U>
    void myFunction(ParameterTypeB b, typename std::enable_if<T == MyCases::CASE2, void>::type* = nullptr) {
        std::cout << "B" << std::endl;
    }
};

int main() {
    MyClass<MyCases::CASE1> m1;
    m1.myFunction(ParameterTypeA{});
    MyClass<MyCases::CASE2> m2;
    m2.myFunction(ParameterTypeB{});
    return 0;
}

输出:

A

B

Live Example


如果不在成员函数之前添加template,您将收到error: no type named 'type' in 'struct std::enable_if<false, void>'错误或类似错误。为了理智,我把它归结为这个例子:

#include <type_traits>

template <typename U>
class Test {
    template <typename T = U>
    void myFunction(int b, typename std::enable_if<std::is_same<int, T>::value, void>::type* = nullptr) {
    }

    template <typename T = U>
    void myFunction(int b, typename std::enable_if<!std::is_same<int, T>::value, void>::type* = nullptr) {
    }
};

int main() {
    Test<int> test;

    return 0;
}

在意识到这一点之后,我修改了第一个人的答案来获得这个。正如您所看到的,此版本中没有enum class,但如果您将typename Utypename T更改为enum MyCases,则其效果就像魔法一样。

#include <type_traits>
#include <iostream>

struct ParameterTypeA {};
struct ParameterTypeB {};

template<typename U>
class MyClass
{
public:
    MyClass() { }
    ~MyClass() { }

    template<typename T = U>
    void myFunction(ParameterTypeA a, typename std::enable_if<std::is_same<ParameterTypeA, T>::value, void>::type* = nullptr) {
        std::cout << "A" << std::endl;
    }

    template<typename T = U>
    void myFunction(ParameterTypeB b, typename std::enable_if<std::is_same<ParameterTypeB, T>::value, void>::type* = nullptr) {
        std::cout << "B" << std::endl;
    }
};

int main() {
    MyClass<ParameterTypeA> m1;

    m1.myFunction(ParameterTypeA{});

    MyClass<ParameterTypeB> m2;

    m2.myFunction(ParameterTypeB{});
    return 0;
}

输出:

A

B

Live Example