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

C++ 使用具有相同参数的不同模板参数重载函数时出错,c++,compiler-errors,overloading,template-templates,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(Te

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

template<template<typename> class TemplArgA, template<typename> class TemplArgB>
class CompileError {
public:
  void func(TemplArgA<int> x) {}
  void func(TemplArgB<int> x) {}
};
模板
类编译器错误{
公众:
void func(TemplArgA x){}
void func(templargbx){}
};
我正在使用VC2010并获取

error C2535: 'void CompileError<TemplArgA,TemplArgB>::func(TemplArgA<int>)': member function already defined or declared
错误C2535:'void CompileError::func(TemplArgA)':成员函数已定义或声明
在编译上面的代码示例时(甚至在模板实例化时都没有,只是为了让代码中的上述行已经导致编译错误)

相比之下,这些标准很好:

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) {}
};
模板
类编译{
公众:
void func(TemplArgA x){}
void func(templargbx){}
};
模板
类也可编译{
公众:
void func(TemplArgA x){}
void func(templargbx){}
};
知道我做错了什么吗

似乎可以用clang++编译,所以我想知道这是否是VC2010中的一个bug。。。如果是这样的话:你知道如何解决这个问题吗

别无选择,必须使用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) {}
模板
类编译器错误{
公众:
void func(templaga x){}
void func(TemplArgB x,void*变通方法=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) {}
//...
模板结构解决方案{};
void func(TemplArgA x,变通方法_t*变通方法=0){}
void func(TemplArgB x,变通方法_t*变通方法=0){}
void func(TemplArgC x,变通方法_t*变通方法=0){}
//...

我想问题是编译器看到并错误地发现可能的IStantation win
TemplArgA==templarargb
(当两个
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)
    { }    

 };
第四个呢

   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)
    { }
模板
typename std::enable_if::类型
func(D4 x)
{ }
)但我希望它能起作用

下面是一个完整的工作示例(但使用g++和clang++;我不使用VC2010)

#包括
#包括
#包括
模板结构foo1{};
模板结构foo2{};
模板结构foo3{};
模板结构foo4{};
模板
结构条
{
无效函数(C1 x)
{ }
模板
typename std::enable_if::类型
func(d2x)
{ }
模板
typename std::enable_if::类型
func(D3 x)
{ }
模板
typename std::enable_if::类型
func(D4 x)
{ }
};
int main()
{
棒b1234;
棒b1111;
棒b1112;
棒b1121;
棒b1211;
棒b2111;
}

找到了适合我的解决方案:

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) {}
};
枚举选择器{S_A,S_B};
模板
类解决方法{
公众:
void func(TemplArg x){}
void func(TemplArg x){}
};
通过这种方式,VC2010编译时没有C2535。这使得作为模板参数提供的类更加复杂。我正式地进行了分类

template<typename T> class MyA { ... };
template<typename T> class MyB { ... };
模板类MyA{…};
模板类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 */ };
模板类MyAB;
模板类MyAB{…};
模板类MyAB{…};
模板类MyA:公共MyAB{/*`forward'构造函数实现*/};
模板类MyB:公共MyAB{/*`forward'构造函数实现*/};
无论如何,使用这种方法,事情看起来要复杂得多,所以我对此并不满意。我将尝试使用Massimiliano编辑的帖子中的建议,认为这会使代码看起来不那么可怕;但为了完整性,我还是想提供这种方法;)


我仍然想知道你是否遗漏了一些重要的东西,或者它是否是VC2010 bug…

为什么不使用2017?没有选择,必须使用VC2010:(VC阻塞了模板定义本身,或者是实例化导致了问题?模板定义本身。我认为TemplArgA==Templargbcase在这两种情况下都不会给出错误,直到函数实例化,不是吗?无论如何,这与我无关。@thilo,不,在您的原始代码中(我的意思是,对于一致的编译器)一旦类模板被实例化,您就会得到一个错误(但是,我不确定这种诊断在多大程度上是标准的,我应该检查一下…)使用建议的解决方法编译,这是一个好主意。但是在实际代码中,我不只有TemplArgA和TemplArgB,而是4个模板参数(说TemplArgA到TemplArgD)--我认为我无法应用解决方法:(@thilo,作为旁注,根据,我确认需要在类模板实例化时对原始代码的ArgA==ArgB情况进行诊断。“我仍然怀疑…”这肯定是一个vc错误,请参阅
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 */ };