Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template alias and specialization

Tags:

c++

Assuming we have

template<typename T> 
struct Foo
{
};

template<typename T> 
struct Bar
{
};

template< template<typename T> class C >
struct Pack
{
    template<typename T>
    using Container = C<T>;
};

Are Foo and Pack<Foo>::Container supposed to be treated as the same thing if we have a specialization for Foo? That is:

template< template<typename T> class C >
struct IsFoo : std::false_type
{
};

template<>
struct IsFoo<Foo> : std::true_type
{
};

static_assert( IsFoo<Foo>::value,                             "Only foos!" );
static_assert( IsFoo< Pack<Foo>::Container >::value,          "Only foos!" ); // ???
static_assert( IsFoo< Pack<Bar>::Container >::value == false, "Not a foo!" );

Is that second assertion correct? What is the expected behavior? Heck, is what I am trying to do even valid?

I tested it on three compilers and I got different results. It seems that for MSVC and CLang, Foo and Pack<Foo>::Container are not the same thing, but GCC disagrees, which is cool, because that is exactly what I wanted.

So, who is right?

PS: I am not sure if I am using the correct terminology on the title, nor inside the body of my question. Suggestions and corrections are more than welcome.

like image 586
user1593842 Avatar asked Jul 24 '16 19:07

user1593842


People also ask

What is an alias template?

Alias templates are a way to give a name to a family of types. Template parameters can be types, non-types, and templates themselves.

What is the use of 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 is an alias C++?

A reference variable is an alias, that is, another name for an already existing variable. Once a reference is initialized with a variable, either the variable name or the reference name may be used to refer to the variable.

What is a function template in C++?

Function templates are special functions that can operate with generic types. This allows us to create a function template whose functionality can be adapted to more than one type or class without repeating the entire code for each type. In C++ this can be achieved using template parameters.


1 Answers

14.5.7 Alias templates

1 A template-declaration in which the declaration is an alias-declaration (Clause 7) declares the identifier to be a alias template. An alias template is a name for a family of types. The name of the alias template is a template-name.

2 When a template-id refers to the specialization of an alias template, it is equivalent to the associated type obtained by substitution of its template-arguments for the template-parameters in the type-id of the alias template.

In your example Foo and Pack<Foo>::Container (no parameter list) are template-names that don't represent a type but only a template. For example Foo<int> and Pack<Foo>::Container<int> would be template-ids and would thus be equivalent.

To my knowledge the standard doesn't specify any equivalence relation between template-names, so MSVC and Clang are right to assume that only identical template-names are equivalent.

But you could still specialize or overload based on the template-id if that is sufficient for your specific use case. e.g.:

template< typename C >
struct IsFoo : std::false_type
{
};

template<class T>
struct IsFoo<Foo<T>> : std::true_type
{
};

static_assert( IsFoo<Foo<int>>::value,                             "Only foos!" );
static_assert( IsFoo< Pack<Foo>::Container<int> >::value,          "Only foos!" );
static_assert( IsFoo< Pack<Bar>::Container<int> >::value == false, "Not a foo!" );

or

template<class T>
void do_stuff(const T&) {}

template<class T>
void do_stuff(const Foo<T>&) {}
like image 95
lowkey Avatar answered Oct 25 '22 18:10

lowkey