Search code examples
c++templatesgccnamespacesclang

clang error "explicit instantiation does not refer to a function template" across multiple namespaces


I'm trying to reuse existing templated functions from a namespace in my own namespace and explicitly instantiate them for code coverage reasons.

The following code compiles with gcc 9.3 but does not compile with clang 10.0.0

namespace bar {
    template<typename T>
    T func(T arg){ return arg;};
}

namespace foo {
    using bar::func;
}

template int foo::func<int>(int);

int main()
{ }

View example here

If i instantiate the template function as

template int bar::func<int>(int);

clang compiles as well. But this is not what i want.

Is it possible to explicitly instantiate a template function across namespaces with clang?

Why do gcc and clang give different results?


Solution

  • You can't do that, I'm afraid. Clang is correct.

    [temp.explicit]

    2 The syntax for explicit instantiation is:

    explicit-instantiation:  
        externopt template declaration

    4 If the explicit instantiation is for a class or member class, the elaborated-type-specifier in the declaration shall include a simple-template-id; otherwise, the declaration shall be a simple-declaration whose init-declarator-list comprises a single init-declarator that does not have an initializer.

    This paragraph tells us that the bit after the template keyword must be both syntactically and semantically a valid declaration for something (and must not contain an initializer, which isn't relevant here). A declaration has several parts, but the one of interest here is the declarator part of the declaration.

    About that we have the following paragraph

    [dcl.meaning] (emphasis mine)

    1 A declarator contains exactly one declarator-id; it names the identifier that is declared. An unqualified-id occurring in a declarator-id shall be a simple identifier except for the declaration of some special functions ([class.ctor], [class.conv], [class.dtor], [over.oper]) and for the declaration of template specializations or partial specializations ([temp.spec]). When the declarator-id is qualified, the declaration shall refer to a previously declared member of the class or namespace to which the qualifier refers (or, in the case of a namespace, of an element of the inline namespace set of that namespace ([namespace.def])) or to a specialization thereof; the member shall not merely have been introduced by a using-declaration in the scope of the class or namespace nominated by the nested-name-specifier of the declarator-id.

    Since your declarator-id in the explicit template instantiation is foo::func, it does not follow the rule laid out in the sentence I marked in bold. That makes your attempt at explicit instantiation ill-formed.

    GCC should have rejected your attempt too.