Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the rules for out-of-line definitions of constrained member templates?

Consider the following code:

template <typename T>
struct S 
{
    template <typename = void>
    static constexpr bool B = true;

    template <std::enable_if_t<S<T>::template B<>, int> = 0>
    void f();
};

template <typename T>
template <std::enable_if_t<S<T>::template B<>, int>>
void S<T>::f() {}

gcc accepts this, but clang rejects it with:

error: out-of-line definition of 'f' does not match any declaration in 'S<T>'

This has been asked about before, but there is no answer there.


On the other hand, if B is not a template, and I write this code:

template <typename T>
struct S 
{
    static constexpr bool B = true;

    template <std::enable_if_t<S<T>::B, int> = 0>
    void f();
};

template <typename T>
template <std::enable_if_t<S<T>::B, int>>
void S<T>::f() {}

clang accepts this, but gcc rejects the code with:

error: no declaration matches 'void S<T>::f()'

So are either of these snippets valid?

like image 320
cigien Avatar asked Aug 29 '20 02:08

cigien


People also ask

What is Typename in template?

" typename " is a keyword in the C++ programming language used when writing templates. It is used for specifying that a dependent name in a template definition or declaration is a type.

Which of the following is true about implementation of templates feature supported in C++?

Which of the following is true about templates. 1) Template is a feature of C++ that allows us to write one code for different data types. 2) We can write one function that can be used for all data types including user defined types. Like sort(), max(), min(), ..etc.

How do I restrict a template type in C ++?

There are ways to restrict the types you can use inside a template you write by using specific typedefs inside your template. This will ensure that the compilation of the template specialisation for a type that does not include that particular typedef will fail, so you can selectively support/not support certain types.

When should I use templates?

A template is a predesigned document you can use to create documents quickly without having to think about formatting. With a template, many of the larger document design decisions such as margin size, font style and size, and spacing are predetermined.


1 Answers

During the definition of S<X> it is an incomplete type. And the class member access operator requires a complete type.

But you could solve the situation with the following code:

#include <type_traits>

template <typename T>
struct S {

    template <typename = void>
    static constexpr bool B = true;

    template <
        typename TX = T,
        std::enable_if_t<S<TX>::template B<>, int> = 0>
    void f();
};

template <typename T>
template <typename TX, std::enable_if_t<S<TX>::template B<>, int>>
void S<T>::f() {}

//-----------

template <typename T>
struct S2 {

    static constexpr bool B = true;

    template <
        typename TX = T,
        std::enable_if_t<S2<TX>::B, int> = 0>
    void f();
};

template <typename T>
template <typename TX, std::enable_if_t<S2<TX>::B, int>>
void S2<T>::f() {}
like image 153
Bernd Avatar answered Oct 07 '22 13:10

Bernd