37

The following code compiles in Clang but does not in GCC:

template<typename T>
struct Widget
{
    template<typename U>
    void foo(U)
    {
    }

    template<>
    void foo(int*)
    {
    }
};

According to the C++ standard ([temp.expl.spec], paragraph 2):

An explicit specialization may be declared in any scope in which the corresponding primary template may be defined

Is this a bug in GCC and if so how can I find it in its bug tracker?

This is GCC's output:

prog.cc:13:14: error: explicit specialization in non-namespace scope 'struct Widget<T>'
     template<>
              ^

I'm using GCC HEAD 8.0.1, with -std=c++2a.

0

2 Answers 2

43

This should be a GCC bug. Full specialization should be allowed in any scope, including in class definition.

According to CWG 727, [temp.expl.spec] paragraph 2 was changed from

(emphasis mine)

An explicit specialization shall be declared in a namespace enclosing the specialized template. An explicit specialization whose declarator-id or class-head-name is not qualified shall be declared in the nearest enclosing namespace of the template, or, if the namespace is inline (10.3.1 [namespace.def]), any namespace from its enclosing namespace set. Such a declaration may also be a definition. If the declaration is not a definition, the specialization may be defined later (10.3.1.2 [namespace.memdef]).

to

(emphasis mine)

An explicit specialization may be declared in any scope in which the corresponding primary template may be defined (10.3.1.2 [namespace.memdef], 12.2 [class.mem], 17.6.2 [temp.mem]).

It seems GCC fails to follow this.

EDIT

I have reported the issue as Bug 85282.

Sign up to request clarification or add additional context in comments.

13 Comments

This is a big change, no need any more of the defaulted dumb template parameter trick to simulate a an explicit template specialization :)!!
Can you clarify which standard changes that? C++17?
@songyuanyao No, not really. The defect report has been retroactively applied to C++14.
@cppBeginner I think Gcc is used; and yes, Gcc still doesn't fix this issue; clang works fine.
@fde-capu Partial specialization was allowed. So let's say you declared a template with template <typename P1> class X, if you wanted to provide a specialization for X you could change the declaration to template <typename P1, typename Dumb = void> class X and then provide a partial specialization template<typename Dumb> class X<Int, Dumb>
|
11

If somebody is looking for a workaround till this is fixed in gcc:

It is possible to use std::is_same_v and if constexpr godbolt

template<typename T>
struct Widget
{
    template<typename U>
    void foo(U)
    {
        if constexpr (std::is_same_v<U, int*>) {
            std::cout << "int*\n";
        }
        std::cout << "U\n";
    }

};

1 Comment

Thanks for this one. Seems to be the only one which works for member functions! :) Ugly if a lot of types are needed but still better to move all the code outside the class and add extra declarations.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.