问题
I have a class that gets two template template parameters and overloads a function with an argument that is either the one or the other template template parameter but both times with the same template argument:
template<template<typename> class TemplArgA, template<typename> class TemplArgB>
class CompileError {
public:
void func(TemplArgA<int> x) {}
void func(TemplArgB<int> x) {}
};
I am using VC2010 and get
error C2535: 'void CompileError<TemplArgA,TemplArgB>::func(TemplArgA<int>)': member function already defined or declared
when compiling the above code sample (not even at template instantiation, just to have the above lines in the code already causes the compile error).
These in contrast compile fine:
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) {}
};
Any idea what I am doing wrong?
Seems to compile fine with clang++, so I wonder whether it might be a bug in VC2010 ... If so: Any idea how to work around it?
回答1:
Don't have a choice, must use VC2010 :(
If so: Any idea how to work around it?
so, you may try
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) {}
of course, this is not strictly equivalent to your original code though (because you'll not get an error until function instantation in the TemplArgA==TemplArgB case; I don't know if this is relevant for you or not)
But in the real code, I don't have just TemplArgA and TemplArgB, but 4 template template parameters (say TemplArgA to TemplArgD) -- I don't think I can apply the workaround then?
you just need to persuade the compiler that those overloads are not equivalent:
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) {}
//...
回答2:
I suppose the problem is that the compiler see and error the possible istantiation win TemplArgA == TemplaArgB
(when the two func()
collide) so I suppose that (if you can use C++11) another workaround is SFINAE enable (or not) the second func()
only id TemplArgA != TemplArgB
I mean something like
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)
{ }
};
The OP add:
in the real code, I don't have just
TemplArgA
andTemplArgB
, but 4 template template parameters (sayTemplArgA
toTemplArgD
)
My solution become really ugly (the third function
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)
{ }
and the fourth
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)
{ }
) but I hope could work.
The following is a full working (but with g++ and clang++; I don't with VC2010) example
#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;
}
回答3:
Found a workaround that works for me:
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) {}
};
This way, VC2010 compiles without C2535. It makes the classes to be provided as template arguments more complicated. I formally had classed
template<typename T> class MyA { ... };
template<typename T> class MyB { ... };
that I used as template arguments, now use partial template specialization like
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 */ };
Anyway, things look much more complicated than they need to be with this approach, so I'm not really satisfied with this. I will try with Massimiliano's suggestion from his edited post, think that will make the code look less frightening; still I wanted to provide this approach for the sake of completeness ;)
I still wonder whether I you missed out something important or whether it is a VC2010 bug ...
来源:https://stackoverflow.com/questions/47057344/error-overloading-function-with-different-template-template-parameters-with-same