Template specialisation implementation

Currently I am struggling to compile the following snippet:

Header:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#ifndef TEST_H
#define TEST_H

#include <vector>

class Test {
public:
	enum Enum {
		OPTION_1 = 0,
		OPTION_2 = 1,
		OPTION_3 = 2
	};

	template <Enum E>
	static void Method();

	typedef void (*Func)();

	static Func GetFunc(int index){
		static const std::vector<Func> table {
			Method<OPTION_1>,
			Method<OPTION_2>,
			Method<OPTION_3>
		};
		return table.at(index);
	}
};


#endif


Source:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include "test.h"

template <> void Test::Method<Test::Enum::OPTION_1>() {
	std::cout << "Option 1" << std::endl;
}

template <> void Test::Method<Test::Enum::OPTION_2>() {
	std::cout << "Option 2" << std::endl;
}

template <> void Test::Method<Test::Enum::OPTION_3>() {
	std::cout << "Option 3" << std::endl;
}


I get the following errors:
1
2
3
4
5
6
7
8
<cut>\test.cpp:4:53: error: specialization of 'static void Test::Method() [with Test::Enum E = (Test::Enum)0]' after instantiation
 template <> void Test::Method<Test::Enum::OPTION_1>() {
                                                     ^
<cut>\test.cpp:8:53: error: specialization of 'static void Test::Method() [with Test::Enum E = (Test::Enum)1]' after instantiation
 template <> void Test::Method<Test::Enum::OPTION_2>() {
                                                     ^
<cut>\test.cpp:12:53: error: specialization of 'static void Test::Method() [with Test::Enum E = (Test::Enum)2]' after instantiation
 template <> void Test::Method<Test::Enum::OPTION_3>() {


I've tried a lot of different ways of writing this. The only condition I have is to have the implementation of the specialized template methods to be in the source file.

I'd be glad if someone points me in the right direction :)
Last edited on
You can't use template specialization with functions. Only with classes.
I would normally assume you're talking nonsense. But assuming your enormous point count translates to experience, I have to take you seriously.

What do you mean by that? What about this? https://www.geeksforgeeks.org/template-specialization-c/
I stand corrected. It used to be forbidden.

I think the problem is that the compiler needs to see that the template is specialized before it sees uses of the function. You could either forward-declare the specializations:
1
2
3
4
template <Enum E>
static void Method();
template <> void Method<Enum::OPTION_1>();
template <> void Method<Enum::OPTION_2>();
or move the definition of GetFunc() to the source, after the specializations. If you're going to use the specializations from other sources, you should forward-declare.
Except for the typedef, which is of course not visible from outside your class, I can compile and execute your code.

To get better answers, *always* provide compilable snippets which reproduce your issue.

Kiryu.hpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifndef TEST_HPP
#define TEST_HPP


using p_to_f = void (*)();


class Test {
public:
    enum Enum {
        OPTION_1 = 0,
        OPTION_2 = 1,
        OPTION_3 = 2
    };

    template <Enum E>
    static void Method();

    static p_to_f GetFunc(int index);
};


#endif // TEST_HPP 


Kiryu.cpp:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include "Kiryu.hpp"
#include <iostream>
#include <vector>


template <> void Test::Method<Test::Enum::OPTION_1>()
{
    std::cout << "Option 1\n";
}


template <> void Test::Method<Test::Enum::OPTION_2>()
{
    std::cout << "Option 2\n";
}


template <> void Test::Method<Test::Enum::OPTION_3>()
{
    std::cout << "Option 3\n";
}


p_to_f Test::GetFunc(int index)
{
    static const std::vector<p_to_f> table {
        Method<OPTION_1>,
        Method<OPTION_2>,
        Method<OPTION_3>
    };
    return table.at(index);
}


main.cpp:
1
2
3
4
5
6
7
8
9
10
#include "Kiryu.hpp"
#include <iostream>


int main()
{
    Test t;
    auto a { t.GetFunc(1) };
    a();
}


Compilation instruction:
g++ -std=c++2a -Werror -Wall -Wextra -Wpedantic -Wshadow -O2 Kiryu.cpp main.cpp -o main.exe

Output:
Option 2

Registered users can post here. Sign in or register to post.