You can put the data in a base class, then use if constexpr :
template<class T> struct C_data{ T m_result; }; template<> struct C_data<void>{ }; template<class T> class C: C_data<T> { static constexpr auto is_void = std::is_same_v<T,void>; public: auto f(){ if constexpr(is_void) return this->m_result; else return; } void todo(){ if constexpr(is_void) this->m_result = doit<T>(); else doit<T>(); } };
But it can be argued that the specialization of class C is cleaner, since the entire member of the template class must depend on all the parameters of the template (otherwise you must separate your class to avoid bloating the code).
Therefore, I would prefer to completely specialize C and make part of class C, which are independent of T, the base class C:
class C_base{ //any thing that is independent of T; }; template<class T> class C: public C_base{ //any thing that depend on T }; template<> class C<void>: public C_base{ //any thing that depend on T; };
You can also specialize a member function with a member function, but I believe it is less pure.
You will find this latest code structure in almost all the headers of standard library implementations.
source share