How to use the using keyword for a variation pattern
I have a variadic templated class that can accept any number of variables in a constructor, std::tuple/std::pair
and so on.
I would like to use this wrapper for functions with different return types.
For example:
class f1
{
using output = double;
output operator() { do_smth };
}
class f2
{
using output = std::tuple<double,int>;
output operator() { do_smth };
}
template <typename... Types>
class OutputType
{
std::tuple<Types...> m_val;
public:
OutputType(std::tuple<Types...>&& val) : m_val(val) {};
OutputType(Types&& ... val) : m_val(std::forward<Types>(Types)...) {};
};
Now in the third class, I would like to declare the following:
template <typename F>
class dummy
{
using Output = typename OutputType(typename F::Output));
}
How do I declare the above statement so that it does the right thing for and for dummy<f2>
?
(i.e. OutputType<double,int>
, not OutputType<std::tuple<double,int>>
)
source to share
If I understand your question correctly (?), You can define type traits as
template <typename ... Types>
struct oTypes
{ using type = OutputType<Types...>; };
template <typename ... Types>
struct oTypes<std::tuple<Types...>>
{ using type = OutputType<Types...>; };
and then define dummy
like this
template <typename F>
struct dummy
{ using output = typename oTypes<typename F::output>::type; };
Below is a complete compiled example
#include <tuple>
#include <utility>
struct f1
{
using output = double;
output operator() ()
{ return 0.0; }
};
struct f2
{
using output = std::tuple<double,int>;
output operator() ()
{ return { 1.0, 2 }; }
};
template <typename ... Types>
class OutputType
{
private:
std::tuple<Types...> m_val;
public:
OutputType(std::tuple<Types...>&& val) : m_val(val)
{ }
OutputType(Types&& ... val) : m_val(std::forward<Types>(val)...)
{ }
};
template <typename ... Types>
struct oTypes
{ using type = OutputType<Types...>; };
template <typename ... Types>
struct oTypes<std::tuple<Types...>>
{ using type = OutputType<Types...>; };
template <typename F>
struct dummy
{ using output = typename oTypes<typename F::output>::type; };
int main()
{
static_assert( std::is_same<dummy<f1>::output,
OutputType<double>>::value, "!");
static_assert( std::is_same<dummy<f2>::output,
OutputType<double, int>>::value, "!!");
}
source to share
A helper template like
template<typename ... Types>
struct add_tuple {
using type = std::tuple<Types...>
};
template<typename ... Types>
struct add_tuple<std::tuple<Types...>> {
using type = std::tuple<Types...>
};
Which changes the OutputType to something like
template <typename... Types>
class OutputType
{
typename add_tuple<Types...>::type m_val;
public:
OutputType(typename add_tuple<Types...>::type&& val) : m_val(val) {};
OutputType(Types&& ... val) : m_val(std::forward<Types>(Types)...) {};
};
source to share