I have typename T1
and I have a parameter pack typename... Variadic
.
I want to create a struct that contains a using alias using Type = ...
to the first type in the parameter pack that T1
can be converted into. So far I have tried the following:
template<typename T1, typename T2, typename... Variadic>
struct VariadicConvertibleType
{
using Type = std::enable_if<std::is_convertible<T1, T2>::value, T2>::type;
};
This could be a potential solution using SFINAE for the first two types, but I need to expand this to all the types in the pack using recursion. All my attempts failed so far, because you can't put conditionals into using alias declarations. Otherwise something similar to this could be used:
template<typename T1, typename T2, typename... Variadic>
struct VariadicConvertibleType
{
using Type = std::is_convertible<T1, T2>::value ? T2 : VariadicConvertibleType<T1, Variadic...>::Type;
};
I can use everything up to (and including) C++14 to implement the solution. I can not using anything other than the standary library though.
Variadic templates are class or function templates, that can take any variable(zero or more) number of arguments. In C++, templates can have a fixed number of parameters only that have to be specified at the time of declaration.
It takes one fixed argument and then any number of arguments can be passed. The variadic function consists of at least one fixed variable and then an ellipsis(…) as the last parameter. This enables access to variadic function arguments. *argN* is the last fixed argument in the variadic function.
With the variadic templates feature, you can define class or function templates that have any number (including zero) of parameters. To achieve this goal, this feature introduces a kind of parameter called parameter pack to represent a list of zero or more parameters for templates.
Parameter packs (C++11) A parameter pack can be a type of parameter for templates. Unlike previous parameters, which can only bind to a single argument, a parameter pack can pack multiple parameters into a single parameter by placing an ellipsis to the left of the parameter name.
You can use std::conditional, like this:
template<typename T1, typename T2, typename... Variadic>
struct VariadicConvertibleType
{
using type = std::conditional_t<std::is_convertible<T1, T2>::value, T2, typename VariadicConvertibleType<T1, Variadic...>::type>;
};
template<typename T1, typename T2>
struct VariadicConvertibleType<T1, T2>
{
static_assert(std::is_convertible<T1, T2>::value);
using type = T2;
// Alternative base-case
// using type = std::conditional_t<std::is_convertible<T1, T2>::value, T2, T1>;
};
I have provided two base-cases (alternative one in comment).
The primary one (which I thing is what you want) uses a (C++14) static_assert
if T1
is not convertible to any of the types in Variadic
. The alternative base-case sets type
to T1
in that case.
Test
#include <iostream>
#include <type_traits>
#include <typeinfo>
int main()
{
using my_type_1 = typename VariadicConvertibleType<int, double, float>::type;
std::cout << typeid(my_type_1).name() << '\n'; // double
using my_type_2 = typename VariadicConvertibleType<int, int*, float>::type;
std::cout << typeid(my_type_2).name() << '\n'; // float
using my_type_3 = typename VariadicConvertibleType<int, int*, float*>::type;
std::cout << typeid(my_type_3).name() << '\n'; // Complile error with the primary base-case, and int with the alternative base-case.
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With