Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding C++ member function template specialization

Tags:

c++

templates

I have the following class:

#pragma once
#include <string>
#include <iostream>

class testclass
{
public:
    template <class T> T item(const std::string& key)
    {
        std::cout << "non-specialized\n";
        return T();
    }
};

For the item method I would like to provide a specialization for strings. I try to do this the following way (in testclass.cpp):

#include "testclass.h"
#include <iostream>

template<> std::string testclass::item(const std::string& key)
{
    std::cout << "specialized\n";
    return std::reverse(key.begin(), key.end());
}

And then I try to call the function like this:

#include <iostream>
#include "testclass.h"

int main()
{
    testclass t;
    std::string key = "foo";
    t.item<int>(key);
    std::string s = t.item<std::string>(key);
    std::cout << s << std::endl;
}

However, the output is

$ ./a.out
non-specialized 
non-specialized
(empty line)

What I excepted was

$ ./a.out
non-specialized 
specialized
oof

How can I do this properly? I am using g++ 4.5.2 to compile the program.

Edit:

The solution is the move the whole definition of the specialization of item to testclass.h (but not into the class). I had other mistakes in the program, such as not including <algorithm> (for reverse), and incorrectly thinking that it would return the reversed string. To achieve the excepted behaviour, the .cpp file is left empty, and the header contents are the following:

#pragma once
#include <string>
#include <iostream>
#include <algorithm>

class testclass
{
    public:
        template <class T> T item(const std::string& key)
        {
            std::cout << "non-specialized\n";
            return T();
        }
};

template<> std::string testclass::item(const std::string& key)
{
    std::cout << "specialized\n";
    std::string s = key;
    std::reverse(s.begin(), s.end());
    return s;
}
like image 443
Tamás Szelei Avatar asked Sep 28 '11 11:09

Tamás Szelei


People also ask

What is function template specialization?

The act of creating a new definition of a function, class, or member of a class from a template declaration and one or more template arguments is called template instantiation. The definition created from a template instantiation is called a specialization.

What are the two specializations of i/o template classes in C ++?

What are the two specializations of I/O template classes in C++? Explanation: The I/O specialization is made with wide character and 8-bit characters.

What is the difference between generic class template and specialization template?

Generics are generic until the types are substituted for them at runtime. Templates are specialized at compile time so they are not still parameterized types at runtime. The common language runtime specifically supports generics in MSIL.

Are template specializations inline?

An explicit specialization of a function template is inline only if it is declared with the inline specifier (or defined as deleted), it doesn't matter if the primary template is inline.


2 Answers

The problem boils down to the common problem of not having the templates in the header file. The compiler, when processing main does not see the specialization and it generates its own instantiation of the generic template for std::string. This is a violation of the ODR, as there are now 2 different specializations for std::string in the same program, but the compiler is not required to diagnose it.

The simple solution is to declare/define the specialization in the header so that the compiler can either use it, or at least will know not to generate the specialization from the generic version when processing main

like image 151
David Rodríguez - dribeas Avatar answered Oct 20 '22 21:10

David Rodríguez - dribeas


Sadly, this is not the whole story. The explicit specialization of the member template function 'item' must be unique throughout the program. If you were to create another translation unit that implemented another function that did the same thing as 'main' and linked that into your program, you would get multiple definitions. You have a couple of alternatives: (1) declare the specialization to be an inline function in the header (not a general solution); (2) declare the specialization in the header and define it in the '.cpp' file (general answer). This is a great example of the importance of understanding at a fundamental level how compilers and linkers implement the "physical linking" of various C++ constructs.

like image 44
John L. Avatar answered Oct 20 '22 22:10

John L.