sbi
sbi

Reputation: 224079

What's the cheapest way to specialize a traits member

I have a traits class that is supposed to provide just one information about other types (in form of a string):

template<typename T>
struct some_traits {
    static const char* const some_string;
};

I need to provide special instances of some_string for each type. The common way I know how to do this is to only declare some_traits, and then write specializations:

template<typename T>
struct some_traits;

template<>
struct some_traits<blah> {
    static const char* const some_string;
};
const char* const some_traits<blah>::some_string = "blah string";

This is, however, a lot of code, when all I need is a specialized some_string. Is there a way to simplify this?

I have tried to fiddle with explicit specializations, but failed to come up with a syntax that doesn't make the compiler spit venomous error messages into my face.

Notes:

Upvotes: 3

Views: 94

Answers (2)

dyp
dyp

Reputation: 39111

It is possible to explicitly specialize members of class templates:

template<typename T>
struct some_traits {
    static const char* const some_string;
};

template<>
char const* const some_traits<int>::some_string = "int";

This should reduce the overhead of declaring new specializations slightly. However, this technique cannot be applied to partial specializations:

template<typename T> struct foo {};
template<typename T>
char const* const some_traits<foo<T>>::some_string = "foo<T>"; // error

... that is, unless you add a partial specialization for some_traits:

template<typename T>
struct some_traits<foo<T>> {
    char const* const some_string;
};

Two alternatives:

(1) Using ADL and functions

template<typename T> struct some_string_tag {};

template<typename T>
struct some_traits {
    static const char* const some_string;
};
template<typename T>
char const* const some_traits<T>::some_string = get_string(some_string_tag<T>());

A specialization can then be written as:

char const* get_string(some_string_tag<int>) { return "int"; }

And partial specializations as:

template<typename T>
char const* get_string(some_string_tag<foo<T>>) { return "foo<T>"; }

(In this case, some_traits is a point for customizing how the string is found, and it provides convenient access to the string as a variable.)

(2) A second trait using an inline function

template<typename T>
char const* const some_traits<T>::some_string = some_traits_X<T>::get_string();

template<typename T> struct some_traits_X {
    // provide: static char const* get_string();
};

template<>
struct some_traits_X<int> {
    static char const* get_string() { return "int"; }
};

template<typename T>
struct some_traits_X<foo<T>> {
    static char const* get_string() { return "foo<T>"; }
};

Upvotes: 7

Benilda Key
Benilda Key

Reputation: 3092

Why not use functions?

template<typename T>
struct some_traits {
    static const char* const some_string();
};

template<>
struct some_traits<blah> {
     static const char* const some_string() { return "blah string"; }
};

Upvotes: -1

Related Questions