我有一个获取两个模板模板参数的类,并使用一个参数重载一个函数,该参数是一个或另一个模板模板参数,但两次都使用相同的模板参数:
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中的一个错误...如果是这样的话:任何想法如何解决它?
答案 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添加:
在真实代码中,我不仅仅有
TemplArgA
和TemplArgB
,而是4个模板模板参数(比如TemplArgA
到TemplArgD
)
我的解决方案变得非常丑陋(第三个功能
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的错误......