1

I have a Painter template class with paint() template function. I am using tagging to specialize template function inside template class. I have placed definition of template function paint() inside Painter.h and overloaded function inside Painter.cpp.

I get compiler error when I explicitly instantiate paint() in Painter.cpp. My requirement is that I need the implementation of overloaded function paint(ColorTag<Color::RED>) in the file Painter.cpp.

Source files are as follows:

Painter.h

#include <iostream>

enum class Color {
    RED = 0,
    GREEN = 1,
    BLUE = 2
};

template<Color>
struct ColorTag {

};

template<typename T>
class Painter {
public:

    template<Color MyColor>
    void paint(ColorTag<MyColor>);
    void paint(ColorTag<Color::RED>);

};

template<typename T>
template<Color MyColor>
void Painter<T>::paint(ColorTag<MyColor>){
    std::cout << "General" << std::endl;
}

Painter.cpp

#include "Painter.h"

template<typename T>
void Painter<T>::paint(ColorTag<Color::RED>){
    std::cout << "RED" << std::endl;
}

template void Painter<int>::paint(ColorTag<Color::RED>);

Main.cpp

#include "Painter.h"

int main(){
    Painter<int> painter;
    painter.paint(ColorTag<Color::RED>());
    return 0;
}

Compiled using

g++ Main.cpp Painter.cpp -std=c++11

I get following compiler error when I explicitly instantiate paint() in Painter.cpp

Painter.cpp:8:15: error: ambiguous template specialization ‘paint<>’ for ‘void Painter<int>::paint(ColorTag<(Color)0>)’
 template void Painter<int>::paint(ColorTag<Color::RED>);
               ^
Painter.cpp:4:6: note: candidates are: void Painter<T>::paint(ColorTag<(Color)0>) [with T = int]
 void Painter<T>::paint(ColorTag<Color::RED>){
      ^
In file included from Painter.cpp:1:0:
Painter.h:20:10: note:                 template<Color MyColor> void Painter<T>::paint(ColorTag<MyColor>) [with Color MyColor = MyColor; T = int]
     void paint(ColorTag<MyColor>);

What I have tried

Firstly I created a template function called instantiatePaint() to call paint() function. Then I placed and instantiated it in Painter.cpp file. This worked. But this kind of feels awkward.

template<typename T>
template<Color MyColor>
void Painter<T>::instantiatePaint(ColorTag<MyColor>){
    paint(ColorTag<MyColor>());
}

template void Painter<int>::instantiatePaint(ColorTag<Color::RED>);

Secondly moved overloaded function definition from Painter.cpp to Painter.h. This works but breaks my requirement of having overloaded function paint(ColorTag<Color::RED>) in Painter.cpp.

Are there any better methods to fix the problem or what exactly is causing the ambiguity?

Vivek
  • 448
  • 2
  • 11

3 Answers3

1

What you want is an explicit specialization with T = int so correct syntax is :

template<> 
void Painter<int>::paint(ColorTag<Color::RED>);

With this syntax, both g++ and clang compile the code. Live example

Pumkko
  • 1,523
  • 15
  • 19
0

Why can't you initialize whole class, instead of function?

template class Painter<int>;
PcAF
  • 1,975
  • 12
  • 20
  • This works until it breaks. There are case where we cannot instantiate entire template class explicitly. Lets say we have two structs that can replace `int`. `struct Box { static void foo(){ std::cout << "foo";} };` `struct Cube { static void bar(){ std::cout << "Cube";} };`. Make template function `paint(ColorTag)` to call `T::bar()` and specialized function to call `T::foo()`. Now try to instantiate the full class using either `Box` or `Cube`. – Vivek Apr 29 '16 at 18:02
  • Firstly note that in your code `paint(ColorTag)` is not template specialization, it's `overloaded` function. Secondly, I don't know if I clearly understand what you want, anywat it's this what you meant: http://ideone.com/euoiPN – PcAF Apr 29 '16 at 20:03
  • Yes template functions cannot be specialized inside template class. But what have done using tagging gives me the effect of pseudo template specialization. **My requirement is that I need the specialized (tagged) function in the Painter.cpp file itself.**. You can see **My attempts to fix** if you read towards the end of my question. As I have said in **my attempts to fix**, the problems is solved easily if I just move pseudo specialized function to `Painter.h` without any _explicit instantiation_ in `Painter.cpp`. – Vivek Apr 30 '16 at 03:09
-1
#include <iostream>

enum Color {
    RED = 0,
    GREEN = 1,
    BLUE = 2
};

template<Color color = Color::RED>
struct ColorTag 
{
    // your Implementation
};

template<>
struct ColorTag <Color::RED>
{
    // your Implementation specific to Color::RED
};

template<typename T>
class Painter {
public:

    // template specialization can not apply on method level
    // use class or struct
    template<Color MyColor> 
    void paint(ColorTag<MyColor>);
};

template<typename T>
template<Color MyColor>
void Painter<T>::paint(ColorTag<MyColor> colorTag)
{
    std::cout << "General"<<std::endl;
}

working fine on visual Studio 2012 not sure about Gcc

Jai
  • 1,292
  • 4
  • 21
  • 41
  • 1
    please answer, you are very much sure that this will 100% work, "not sure" makes it dicey – piyushj Apr 29 '16 at 08:12
  • because I have not checked it on GCC, I read somewhere double template is compiler dependent. – Jai Apr 29 '16 at 09:03