I have a class Data that holds a significant amount of functions. That class may also have 0 or N additional types that are necessary in the implementation of the functions of the class:
// in Data.h
template <typename T, typename ...Args>
class Data
{
T f1();
T f2() const;
... // skipped
void f10(const T& v);
// Pimpl
struct Impl;
Impl* _imp;
};
However, the implementation of some of the functions (but not all!) are completely different if sizeof...(Args) == 0
and if sizeof...(Args) > 0
:
Mainly, the internal private implementation class contains different types.
// in DataImpl.h
template <typename T, typename ...Args>
struct ImplementationSpecificData;
template <typename T>
struct ImplementationSpecificData<T>
{
// Some members available when sizeof...(Args) == 0
};
template <typename T, typename ...Args>
struct ImplementationSpecificData<T, Args...>
{
// Some members available when sizeof...(Args) > 0
};
// The pimpl
template <typename T, typename ...Args>
struct Data<T,Args...>::Impl
{
// Some common members
...
// Following are specific whether sizeof...(Args) is > 0 or == 0
ImplementationSpecificData<T,Args...> specificData;
};
// In Data.cpp
#include "DataImpl.h"
Then, for functions that have an implementation that relies on specificData, I would like to specialize the functions, e.g:
template <typename T, typename ...Args>
T
Data<T,Args...>::f1() {
// Case where sizeof...(Args) > 0
}
// The following won't work because this is partial member template specialization
template <typename T>
T
Data<T>::f1() {
// Case where sizeof...(Args) == 0
}
I tried to use an extra Enable template boolean and specialize functions that needed
template <typename T, bool Enable, typename ...Args>
class Data
{
...
};
template <typename T, typename ...Args>
T
Data<T,
std::integral_constant<bool, sizeof...(Args) > 0>::value,
Args...>::f1() {
// Case where sizeof...(Args) > 0
}
template <typename T, typename ...Args>
T
Data<T,
std::integral_constant<bool, sizeof...(Args) == 0>::value,
Args...>::f1() {
// Case where sizeof...(Args) == 0
}
But that doesn't work either, I get the following:
nested name specifier Data<T, std::integral_constant<bool, (sizeof...(Args) > 0)>::value, Args...>::
for declaration does not refer into a class, class template or class template partial specialization
Is there an elegant way of achieving this, without polluting my API with a base class that contains pure virtual functions and derived class D1 without additional types and a derived class D2 with additional types: that would require to maintain the functions signature of the class (and there are a lot of functions) across all those 3 classes (Base, D1 and D2).
Data<T,Arg1,Args...>::f1()
? – Yolastd::integral_constant<bool, (sizeof...(Args) > 0)>
? I mean: adding a couple of parentheses to avoid that the>
in> 0
is confused with the end ofintegral_constant
. – max66