避免在C ++模板中碰撞成员

时间:2014-06-19 23:01:24

标签: c++ templates

我有一个班级

template <typename T, typename W>
class A {
    void foo(W);
    void foo(T);
    void foo(int);
}

T=intW=intW=T时,此类无法编译。如何让方法优先于彼此?

我想要优先级W > T > int。因此,如果忽略W=Tfoo(T),则会调用foo(W)。如果T=int,则忽略foo(int)并调用foo(T)

编译器是VS2012,但我也有Linux,并且也会考虑GCC / Clang解决方案。任何编译在任何主流编译器上的东西都会出现,但前提是你说它的工作原理是什么编译器。

5 个答案:

答案 0 :(得分:3)

我会标记发送。覆盖调度很容易理解和扩展。

我们从一个完美的货运代理开始:

template<class U> void foo(U&&u){
  foo( std::forward<U>(u), std::is_convertible<U, W>{}, std::is_convertible<U,T>{} );
}

它会创建标记类型,在本例中为true或false类型,以便分发。

这一个:

void foo( W, std::true_type, ... );

捕获可转换为W的所有内容。

接下来,我们阻止这一个:

void foo( T, std::false_type, std::true_type );

来自于考虑第一个参数可以转换为W的情况。

最后,这一个:

void foo( int, std::false_type, std::false_type );
只有在第一个参数无法转换为任何参数时才能考虑

Fancier标签类型,或者一次调度一个,都是可能的。

抱歉打字错误。

我使用单个C ++ 11特性 - {}来构造一个对象 - 上面。如果您的编译器缺乏对该C ++ 11功能的支持,只需升级您的编译器,它就是2014年,随便使用它。如果做不到,请将{}替换为()

答案 1 :(得分:2)

使用std::enable_if

#include <type_traits>

template <typename T, typename W>
struct A {
    void foo(W) {}
    template<typename XT=T> typename std::enable_if<std::is_same<XT,T>::value
      && !std::is_same<T, W>::value, void>::type foo(T) {}
    template<typename XT=int> typename std::enable_if<std::is_same<XT,int>::value
      && !std::is_same<int, T>::value
      && !std::is_same<int, W>::value, void>::type foo(int) {}
};

已添加用于测试:

template struct A<short,char>;
template struct A<char,char>;
template struct A<char,int>;
template struct A<int,char>;
template struct A<int, int>;

struct S {};

int main() {
    A<S, int>{}.foo(S{});
}

答案 2 :(得分:1)

对于模板的相关部分,您可以使用speclializations:

template <typename U, typename W>
struct Foo
{
    void f(U);
    void f(W);
};

template <typename T>
struct Foo<T, T>
{
    void f(T);
};

对于您的类或类模板的其余部分,您可以继承Foo<A, B>,这样您就可以将公共代码保留在需要专门化的部分之外:

template <typename A, typename B>
struct TheClass : Foo<A, B>
{
    // common code
};

答案 3 :(得分:0)

尝试模板专精:

template <typename T, typename W>
class A {
    void foo(W);
    void foo(T);
    void foo(int);
};

template <typename T>
class A<T, T> {
    void foo(T);
    void foo(int);
};
template <>
class A<int, int> {
    void foo(int);
};

答案 4 :(得分:0)

这是一个没有A特化的解决方案,但有几种形式的两个辅助结构。

#include <iostream>

template<typename T, typename W>
struct T_type { typedef T type; };
template<typename W>
struct T_type<W, W>  { typedef void* type; /*dummy type*/};

template<typename T, typename W>
struct int_type { typedef int type; };
template<typename W>
struct int_type<int, W> { typedef void** type; /*dummy type*/};
template<typename T>
struct int_type<T, int> { typedef void** type; /*dummy type*/};
template<>
struct int_type<int, int> { typedef void** type; /*dummy type*/};

template<typename T, typename W>
class A {
public:
    void foo(W w) {
        std::cout << "foo(W)" << std::endl;
    }
    void foo(typename T_type<T, W>::type t) {
        std::cout << "foo(T)" << std::endl;
    }
    void foo(typename int_type<T, W>::type i) {
        std::cout << "foo(int)" << std::endl;
    }
};

int main() {
    std::cout << "A<float, char>" << std::endl;
    A<float, char> a;
    a.foo(1.0f);
    a.foo('1');
    a.foo(1);

    std::cout << "A<float, float>" << std::endl;
    A<float, float> b;
    b.foo(1.0f);
    b.foo(1);

    std::cout << "A<int, int>" << std::endl;
    A<int, int> c;
    c.foo(1);

    return 0;
}