Reputation: 717
#include <iostream>
#include <string>
template<typename U>
struct A
{
template<typename... Ts> auto func();
template<> auto func<int>();
};
template<typename U>
template<>
auto
A<U>::func<int>() { return std::string{"foo"}; }
int main()
{
A<float> a{};
std::cout << a.func<int>() << std::endl;
}
This does not work as specialization of template members of template classes is not possible unless you also specialize the class. (I read about that.)
But if you move the definition of the member specialization to the class definition, it does work:
#include <iostream>
#include <string>
template<typename U>
struct A
{
template<typename... Ts> auto func();
template<> auto func<int>() { return std::string{"foo"}; }
};
int main()
{
A<float> a{};
std::cout << a.func<int>() << std::endl;
}
I'm not sure I fully understand why. Also, while it is working with clang, it does not compile with gcc. So which one is right?
But my real question is, assuming clang is getting it right, why this again is not working:
#include <iostream>
#include <string>
template<typename U>
struct A
{
template<typename... Ts> auto func();
template<> auto func<U>() { return std::string{"foo"}; }
};
int main()
{
A<int> a{};
std::cout << a.func<int>() << std::endl;
}
It is a different error, not specialization of member of unspecialized template, but rather the complaint is that func<int>
with deduced return type cannot be used before it is defined.
Upvotes: 4
Views: 1198
Reputation: 11028
If we look at n4810 § 13.8.3
- A member function, a member function template, a member class, a member enumeration, a member class template, a static data member, or a static data member template of a class template may be explicitly specialized for a class specialization that is implicitly instantiated; in this case, the definition of the class template shall precede the explicit specialization for the member of the class template. If such an explicit specialization for the member of a class template names an implicitly-declared special member function (11.3.3), the program is ill-formed.
You are however allowed to do this, where both are specialized:
template<typename U>
struct A
{
template<typename... Ts> auto func() { /* ... */ }
};
template <>
template <>
auto A<int>::func<int>()
{
// ok, enclosing class template explicitly specialized
}
While this is invalid c++:
template <typename U>
template <>
auto A<U>::func<int>()
{
// ops: invalid, enclosing class template not explicitly specialized
}
According to:
- In an explicit specialization declaration for a member of a class template or a member template that appears in namespace scope, the member template and some of its enclosing class templates may remain unspecialized, except that the declaration shall not explicitly specialize a class member template if its enclosing class templates are not explicitly specialized as well.
And because of:
- A declaration of a function template, class template, or variable template being explicitly specialized shall precede the declaration of the explicit specialization.
Therefore this should not be inside the outer template declaration:
template <typename U>
struct A {
template<typename...Ts> auto func();
template<> auto func<int>() { return std::string{"foo"}; } // should not work
};
I do not know why clang permits this.
But it is allowed to be in the namespace scope where the primary template was declared, in this case global namespace scope.
Upvotes: 1