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;
}
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();
}
std::type_identity
is C++20 but can be rewritten for earlier version