Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When can you specialize a template on a private member type?

Tags:

c++

templates

Given these definitions

template<class T> class foo {};
template<class T> class foo1 { static int i; };
class bar { class baz {}; };

I'm surprised to see that this compiles

template<>
class foo<bar::baz> {};

but this fails with the error 'class bar::baz' is private

template<>
int foo1<bar::baz>::i = 42;

When does this happen, and is there a workaround other than making the type public?

like image 773
Dan Avatar asked Jun 24 '15 17:06

Dan


People also ask

Can a member function be a template?

Member functions can be function templates in several contexts. All functions of class templates are generic but aren't referred to as member templates or member function templates. If these member functions take their own template arguments, they're considered to be member function templates.

What is a template specialization?

The act of creating a new definition of a function, class, or member of a class from a template declaration and one or more template arguments is called template instantiation. The definition created from a template instantiation is called a specialization.

What are the two specializations of i/o template classes in C ++?

What are the two specializations of I/O template classes in C++? Explanation: The I/O specialization is made with wide character and 8-bit characters.

How would you define member function of template class?

Member functions of class templates (C++ only)You may define a template member function outside of its class template definition. The overloaded addition operator has been defined outside of class X . The statement a + 'z' is equivalent to a. operator+('z') .


1 Answers

Consider CWG #182:

Certain access checks are suppressed on explicit instantiations. 14.7.2 [temp.explicit] paragraph 8 says […] I was surprised that similar wording does not exist (that I could find) for explicit specializations. I believe that the two cases should be handled equivalently in the example below (i.e., that the specialization should be permitted).

template <class T> struct C {
  void f();
  void g();
};

template <class T> void C<T>::f(){}
template <class T> void C<T>::g(){}

class A {
  class B {};
  void f();
};

template void C<A::B>::f();    // okay
template <> void C<A::B>::g(); // error - A::B inaccessible

[…]

Rationale (October 2002):

We reconsidered this and decided that the difference between the two cases (explicit specialization and explicit instantiation) is appropriate. The access rules are sometimes bent when necessary to allow naming something, as in an explicit instantiation, but explicit specialization requires not only naming the entity but also providing a definition somewhere.

GCC and Clang do indeed reject the last line of the example shown, which is - apparently - inconsistent behavior, as for a corresponding explicit specialization of a class template, they do not issue an error message:

template <class> struct T {
    void g();
};

class A { class B; class C; };

template <> struct T<A::B>;    // Ok
template <> void T<A::C>::g(); // Error

Demo. So I'll go out on a limb here and call both cases you showed ill-formed by §14.3/3:

The name of a template-argument shall be accessible at the point where it is used as a template-argument.

like image 135
Columbo Avatar answered Sep 28 '22 00:09

Columbo