我有一个类,它获取两个模板模板参数,并使用一个或另一个模板模板参数但两次使用相同的模板参数的参数重载函数:
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 中的错误......如果是这样:知道如何解决它吗?
别无选择,必须使用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) {}
//...
问题是编译器看到并错误了可能的 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;
}
找到了一个适合我的解决方法:
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 */ };
无论如何,事情看起来比这种方法需要的要复杂得多,所以我对此并不满意。我会尝试使用马西米利亚诺在他编辑的帖子中的建议,认为这将使代码看起来不那么可怕;为了完整起见,我仍然想提供这种方法;)
我仍然想知道我是否错过了一些重要的东西,或者它是否是 VC2010 错误......