Error overloading function with different template template parameters with same argument

我怕爱的太早我们不能终老 提交于 2019-12-10 21:05:40

问题


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 and TemplArgB, but 4 template template parameters (say TemplArgA to TemplArgD)

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!