Background information
I am working on a dataflow-like design pattern. The two classes presented below are meant to represent an output data dispatch mechanism. level1
is a CRTP base class. getOutput<N>
in level1
is the function that can be used for getting the output data from an instance of a derived class. Depending on the template parameter N
it calls one of the user defined getOutputImpl
functions. These functions are meant to be provided in a (CRTP-style) derived class. Each of the getOutputImpl
defines an output port associated with the user defined derived class. The input type of the getOutputImpl
is defined by design. The output type of the getOutputImpl
methods can vary. However, by design, the output type must have a structure std::unique_ptr<TOutputType>
, where TOutputType can be any class. More background information can be found here: previous question.
Question
To allow for automatic recognition of the number of the user defined ports (i.e. getOutputImpl
methods) a method getOutputPortsNumber(void)
is provided in the base level1
class. This method is based around the idea that the return type of all user defined getOutputImpl
functions is std::unique_ptr<TOutputType>
. Thus, one can define an additional getOutputImpl
method in the base class that does not have this return type (e.g. it has a void
return type: void getOutputImpl(...)
).
The methodology described above works if the void getOutputImpl(...)
is defined within the user-defined derived class (DataflowOutputClass
in this example) along with other user-defined std::unique_ptr<TOutputType> getOutputImpl(...)
methods. However, when the additional void getOutputImpl(...)
method is moved to the base level1
class, I get a compilation error: no matching function for call to 'DataflowOutputClass<int>::getOutputImpl(PortIdxType<2ul>, const PolyIndex&) const
.
Code
typedef size_t Index;
typedef unsigned long Natural;
typedef std::vector<Index> PolyIndex;
typedef const PolyIndex& crPolyIndex;
template<Index N> struct PortIdxType{};
template<typename TLeafType>
class level1
{
public:
TLeafType* asLeaf(void)
{return static_cast<TLeafType*>(this);}
TLeafType const* asLeaf(void) const
{return static_cast<TLeafType const*>(this);}
template <Index N>
auto getOutput(crPolyIndex c_Idx) const
{return asLeaf() -> getOutputImpl(PortIdxType<N>{}, c_Idx);}
static constexpr Natural getOutputPortsNumber(void)
{return getOutputPortsNumberImpl<0>();}
template<Index N>
static constexpr std::enable_if_t<
std::is_void<
decltype(
std::declval<TLeafType*>() ->
getOutput<N>(PolyIndex({}))
)
>::value,
Index
> getOutputPortsNumberImpl(void)
{return N;}
template<Index N>
static constexpr std::enable_if_t<
!std::is_void<
decltype(
std::declval<TLeafType*>() ->
getOutput<N>(PolyIndex({}))
)
>::value,
Index
> getOutputPortsNumberImpl(void)
{return getOutputPortsNumberImpl<N + 1>();}
template<Index N>
void getOutputImpl(
PortIdxType<N>, crPolyIndex c_Idx
) const
{throw std::runtime_error("Wrong template argument.");}
};
template<typename T>
class DataflowOutputClass:
public level1<DataflowOutputClass<T>>
{
public:
// if void getOutputImpl(...) const is moved here from level1,
// then the code compiles and works correctly.
//overload for when N = 0
std::unique_ptr<double> getOutputImpl(
PortIdxType<0>, crPolyIndex c_Idx
) const
{
std::unique_ptr<double> mydouble(new double(10));
return mydouble;
}
//overload for when N = 1
std::unique_ptr<int> getOutputImpl(
PortIdxType<1>, crPolyIndex c_Idx
) const
{
std::unique_ptr<int> myint(new int(3));
return myint;
}
};
int main()
{
DataflowOutputClass<int> a;
std::cout << a.getOutputPortsNumber() << std::endl;
}
Aucun commentaire:
Enregistrer un commentaire