Search code examples
c++templatesc++14template-specializationclass-template

Why can't I use templates members in its specialization?


Here's my code:

#include <iostream>

template <typename T>
struct Foo
{
public:
    T DataMember;
};

template<>
struct Foo<int>
{
public:
    void bar()
    {
        std::cout << DataMember;
    }
};

When I try to compile it, it gives an

error C2065 'DataMember': undeclared identifier

What I want to do is to use templates members in its specialization.

I tried a lot of things and googled the problem for hours, but everything I find is examples that don't use templates members and other questions related to c++ templates, but not the one I need.


Solution

  • You have mixed up the concept of inheritance and class template specialization. When you specialize Foo for int, you are instructing the compiler to disregard the generic template definition entirely and instead focus solely on the specialized version provided for Foo<int>. The template<> struct Foo<int> has hence no DataMember; therefore the compiler error!

    Depending upon the use case, you might end up mainly

    • either SFINAE (Substitution Failure Is Not An Error) (Since you are using C++14) along with template specialization.

      #include <type_traits> // For std::enable_if
      
      // Primary template for Foo
      template <typename T, typename = void> struct Foo
      {
          T DataMember;
      };
      
      // Specialization for Foo<int> with a bar() member function
      template <typename T>
      struct Foo<T, std::enable_if_t<std::is_same<T, int>>
      {
          T DataMember; // you have to repeat "DataMember" here!
      
          void bar()
          {
              std::cout << DataMember;
          }
      };
      

      See live Demo

    • or You can use std::enable_if (i.e. SFINAE) directly within the primary template to conditionally enable the bar() member function based on the type T.

      template <typename T>
      struct Foo
      {
          T DataMember;
      
          // Enable bar() only for T being int
          template <typename U = T
                  , std::enable_if_t<std::is_same<U, int>::value>* = nullptr>
          void bar()
          {
              std::cout << DataMember;
          }
      };
      

      See live Demo

    • In , you could use , and since you would use much elegant s for the above.