Explicit specialization in non-namespace scope does not compile in GCC
Asked Answered
G

2

36

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.

Gunning answered 7/4, 2018 at 12:3 Comment(0)
M
38

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.

Melancon answered 7/4, 2018 at 12:26 Comment(13)
This is a big change, no need any more of the defaulted dumb template parameter trick to simulate a an explicit template specialization :)!!Sunfish
Can you clarify which standard changes that? C++17?Decretive
@Decretive Yes it's changed since C++17. You may check the different description in C++14(draft N4140) and C++17(draft N4659).Melancon
@Melancon No, not really. The defect report has been retroactively applied to C++14.Gunning
Great reference! After some testing, I found that Clang C++17 still does not allow it. Evidence : coliru.stacked-crooked.com/a/4477a9354f6cba2d Do you have any idea? Thank.Omnibus
@Omnibus You meant Gcc?Melancon
I am not sure. I notice both "clang++" and "g++" in the bottom of the coliru web page. I am new to this stuff. Thank.Omnibus
@Omnibus I think Gcc is used; and yes, Gcc still doesn't fix this issue; clang works fine.Melancon
So far, this does not seem fixed and gcc dev claims that cwg727 never was approved.Baugh
@Swift-FridayPie: No one has claimed that—only that it shouldn’t be allowed in language modes prior to -std=c++17. That said, I think that’s in error.Flagstaff
@DavisHerring some compiler supported it for ages..at work I work with one from 2009 and it got C++17\C++14 features for templates or lambdas, like this syntax, but doesn't support variadic templates or range-based for!Baugh
@Oliv, how does the "dumb template parameter trick" work?Longbow
@Longbow 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>Sunfish
N
10

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";
    }

};
Nichol answered 21/7, 2022 at 18:37 Comment(1)
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.Fin

© 2022 - 2024 — McMap. All rights reserved.