使用具有相同参数的不同模板模板参数重载函数时出错

时间:2017-11-01 14:36:55

标签: c++ compiler-errors overloading template-templates

我有一个获取两个模板模板参数的类,并使用一个参数重载一个函数,该参数是一个或另一个模板模板参数,但两次都使用相同的模板参数:

template<template<typename> class TemplArgA, template<typename> class TemplArgB>
class CompileError {
public:
  void func(TemplArgA<int> x) {}
  void func(TemplArgB<int> x) {}
};

我正在使用VC2010并获得

error C2535: 'void CompileError<TemplArgA,TemplArgB>::func(TemplArgA<int>)': member function already defined or declared

编译上面的代码示例时(甚至在模板实例化时,只是让代码中的上述行已经导致编译错误)。

相比之下编译好:

template<class TemplArgA, class TemplArgB>
class Compiles {
public:
  void func(TemplArgA x) {}
  void func(TemplArgB x) {}
};

template<template<typename> class TemplArgA, template<typename> class TemplArgB>
class AlsoCompiles {
public:
  void func(TemplArgA<int>    x) {}
  void func(TemplArgB<double> x) {}
};

知道我做错了吗?

似乎用clang ++编译得很好,所以我想知道它是否可能是VC2010中的一个错误...如果是这样的话:任何想法如何解决它?

3 个答案:

答案 0 :(得分:2)

  

没有选择,必须使用VC2010 :(

     

如果是这样:任何想法如何解决它?

所以,你可以试试

template<template<typename> class TemplArgA, template<typename> class TemplArgB>
class CompileError {
public:
void func(TemplArgA<int> x) {}
void func(TemplArgB<int> x,void* workaround = 0) {}

当然,这并不完全等同于您的原始代码(因为在TemplArgA == TemplArgB案例中函数即时之前您不会收到错误;我不知道这是否与你或不)

  

但是在实际代码中,我不仅仅有TemplArgA和TemplArgB,而是4个模板模板参数(比如TemplArgA到TemplArgD) - 我不认为我可以应用解决方法吗?

你只需要说服编译器那些重载不等效:

template<int> struct workaround_t{};

void func(TemplArgA<int> x, workaround_t<0>* workaround = 0) {}
void func(TemplArgB<int> x, workaround_t<1>* workaround = 0) {}
void func(TemplArgC<int> x, workaround_t<2>* workaround = 0) {}
//...

答案 1 :(得分:0)

我想问题是编译器看到并错误了可能的istantiation win TemplArgA == TemplaArgB(当两个func()碰撞时)所以我想(如果你可以使用C ++ 11)另一个解决方法是SFINAE启用(或不启用)第二个func()唯一ID TemplArgA != TemplArgB

我的意思是

template <template <typename> class C1, template <typename> class C2>
struct bar
 {
   void func (C1<int> x)
    { }

   template <template <typename> class D2 = C2>
   typename std::enable_if<    std::is_same<C2<int>, D2<int>>{}
                       &&  ( ! std::is_same<C1<int>, D2<int>>{})>::type
      func (D2<int> x)
    { }    

 };

OP添加:

  

在真实代码中,我不仅仅有TemplArgATemplArgB,而是4个模板模板参数(比如TemplArgATemplArgD

我的解决方案变得非常丑陋(第三个功能

   template <template <typename> class D3 = C3>
   typename std::enable_if<    std::is_same<C3<int>, D3<int>>{}
                        && ( ! std::is_same<C1<int>, D3<int>>{})       
                        && ( ! std::is_same<C2<int>, D3<int>>{})>::type
      func (D3<int> x)
    { }

和第四次

   template <template <typename> class D4 = C4>
   typename std::enable_if<    std::is_same<C4<int>, D4<int>>{}
                        && ( ! std::is_same<C1<int>, D4<int>>{})       
                        && ( ! std::is_same<C2<int>, D4<int>>{})       
                        && ( ! std::is_same<C3<int>, D4<int>>{})>::type
      func (D4<int> x)
    { }

)但我希望能奏效。

以下是完整的工作(但是使用g ++和clang ++;我没有使用VC2010)示例

#include <limits>
#include <iostream>
#include <type_traits>


template <typename> struct foo1 { };
template <typename> struct foo2 { };
template <typename> struct foo3 { };
template <typename> struct foo4 { };


template <template <typename> class C1, template <typename> class C2,
          template <typename> class C3, template <typename> class C4>
struct bar
 {
   void func (C1<int> x)
    { }

   template <template <typename> class D2 = C2>
   typename std::enable_if<    std::is_same<C2<int>, D2<int>>{}
                       &&  ( ! std::is_same<C1<int>, D2<int>>{})>::type
      func (D2<int> x)
    { }

   template <template <typename> class D3 = C3>
   typename std::enable_if<    std::is_same<C3<int>, D3<int>>{}
                        && ( ! std::is_same<C1<int>, D3<int>>{})       
                        && ( ! std::is_same<C2<int>, D3<int>>{})>::type
      func (D3<int> x)
    { }

   template <template <typename> class D4 = C4>
   typename std::enable_if<    std::is_same<C4<int>, D4<int>>{}
                        && ( ! std::is_same<C1<int>, D4<int>>{})       
                        && ( ! std::is_same<C2<int>, D4<int>>{})       
                        && ( ! std::is_same<C3<int>, D4<int>>{})>::type
      func (D4<int> x)
    { }
 };


int main ()
 {
   bar<foo1, foo2, foo3, foo4>  b1234;
   bar<foo1, foo1, foo1, foo1>  b1111;
   bar<foo1, foo1, foo1, foo2>  b1112;
   bar<foo1, foo1, foo2, foo1>  b1121;
   bar<foo1, foo2, foo1, foo1>  b1211;
   bar<foo2, foo1, foo1, foo1>  b2111;
 }

答案 2 :(得分:0)

找到适合我的解决方法:

enum eSelector { S_A, S_B };

template<template<typename,eSelector> class TemplArg>
class Workaround {
public:
  void func(TemplArg<int, S_A> x) {}
  void func(TemplArg<int, S_B> x) {}
};

这样,VC2010无需C2535即可编译。它使得作为模板参数提供的类更复杂。我正式入选了

template<typename T> class MyA { ... };
template<typename T> class MyB { ... };

我用作模板参数,现在使用部分模板专门化,如

template<typename T, eSelector S> class MyAB;
template<typename T> class MyAB<T, S_A> { ... };
template<typename T> class MyAB<T, S_B> { ... };

template<typename T> class MyA : public MyAB<T, S_A> { /* `forward' constructor implementations */ };
template<typename T> class MyB : public MyAB<T, S_B> { /* `forward' constructor implementations */ };

无论如何,事情看起来比他们需要这种方法复杂得多,所以我对此并不满意。我将尝试Massimiliano从他编辑的帖子中提出的建议,认为这将使代码看起来不那么可怕;我仍然想为了完整性而提供这种方法;)

我仍然想知道你是否错过了一些重要的事情,或者它是否是VC2010的错误......