c++c++11templatestemplate-specialization

Templated specialization of method in templated class


I have a templated class Widget, which can store either primitive types, or types of another templated class Foo. I would like to access value stored in Widget directly for primitive types, or by calling Foo<>.value() method.

So far I managed to do this with full specialization of Widget for, say Foo<float>. But I would like to be able to have a generic version for Foo<> if possible?

Also, is it possible to keep specialization inside the class declaration?

Ideally, I would like to use features of C++11 or C++14 (no higher).

#include <iostream>

template <class T>
class Foo
{
public:
  T value() const {return v;}
  T v, y;
};


template <class T>
class Widget
{
public:
  // Internal helper to deduce the value_type
  template<typename U>
  struct ValueType { using type = U; };
  //Specialised template Foo
  template<typename U>
  struct ValueType<Foo<U>> { using type = U; };
  using value_type = typename ValueType<T>::type;
  
  Widget(){}

  //Want to have a specialized version of this method
  const value_type Value() const;

  T _value;
};

//Generic version
template <class T>
const typename Widget<T>::value_type Widget<T>::Value() const
{ 
  std::cout << " (call of general Value) ";
  return _value; 
}

//Specialized version for Foo<float>, but what about for Foo<double>?
template <> 
const typename Widget<Foo<float>>::value_type 
Widget<Foo<float>>::Value() const
{ 
  std::cout << " (call of specialized Value for Foo<float>) ";
  return _value.value(); 
}
 

int main() 
{
  Widget<float> w_float;   
  Widget<Foo<float>> w_Foo_f;
  Widget<Foo<double>> w_Foo_d;
  
  w_float._value=10;
  w_Foo_f._value={20, 30};
  w_Foo_d._value={50, 60};
  
  std::cout << "Widget<float> value      = " << w_float.Value() << std::endl;
  std::cout << "Widget<Foo<float>> value = " << w_Foo_f.Value() << std::endl;
  //Oops 
  //std::cout << "Widget<Foo<double>> value = " << w_Foo_d.Value() << std::endl;
  return 0;
}

Solution

  • There is if constexpr in C++17,

    before tag dispatching might help:

      const value_type Value() const { return ValueImpl(std::type_identity<T>{}); }
    
    private:
      template <typename U>
      const value_type ValueImpl(std::type_identity<U>) const {
        std::cout << " (call of general Value) ";
        return _value; 
      }
    
      template <typename U>
      const value_type ValueImpl(std::type_identity<Foo<U>>) const {
        std::cout << " (call of specialized Value for Foo<float>) ";
        return _value.value(); 
      }
    

    Demo

    std::type_identity is C++20 but can be rewritten for earlier version