4
votes
#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.

1
None of these should compile. Template specializations are only allowed to be declared at namespace scope.Brian Bi
@Brian can you please elaborate when you say template specializations are allowed at namespace scopePapaDiHatti
@Kapil What part of this would you like me to elaborate on?Brian Bi
Even if i add this template declaration inside some namespace then also i will get same error so what it means when you say template specialization only allowed at namespace scopePapaDiHatti
this code is working fine with clang, there seems to be some issue with gcc wandbox.org/permlink/R3dM6pQpsNR5IWjePapaDiHatti

1 Answers

1
votes

If we look at n4810 § 13.8.3

  1. 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:

  1. 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:

  1. 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.