在下面的示例中,我试图基本上为模板参数包添加别名。
这在标准中是不可能的,所以我发现人们使用元组或空模板结构来解决限制。但是我的情况似乎不同,因为我没有参数类型包匹配 ...
(我知道这个示例看起来很愚蠢,但它是一个最小的PoC。在代码库中,类型列表会变得更长,这真的很有用。)
<iframe id="main" src="/include/main.html.twig"></iframe>
的引用;
答案 0 :(得分:2)
如果我们使用模板化的空结构来对类型包进行别名,则可以在原始函数上使用 SFINAE ,这样当为我们的特殊结构调用它时,它只是转发封装的类型包到最初的实施。
以下是 C ++ 14 :
中的内容template <typename... Types>
struct TypePack {};
// Helper meta functions to determine
// if the template param is a TypePack struct.
template <typename... Ts>
static constexpr bool is_typepack_v = false;
template <typename... Ts>
static constexpr bool is_typepack_v<TypePack<Ts...>> = true;
template <typename... Ts>
// Enabled whenever template parameter is not a TypePack.
typename std::enable_if<not is_typepack_v<Ts...>>::type
fn() { // FN_A
std::cout << "Generic\n";
}
template <>
// Complete specialization, selected over generic fn for <char,int>
void fn<char,int> () { // FN_B
std::cout << "Specialized for char,int\n";
}
template <typename T>
// Enabled when template param is a TypePack.
typename std::enable_if<is_typepack_v<T>>::type
fn() { // FN_C
forward_fn(T{});
}
// forward_fn() extracts the types from a TypePack argument
// and invokes fn with it.
template <typename ...T>
void forward_fn(TypePack<T...> /*unused*/) {
std::cout << "Forwarding a pack alias\n";
fn<T...>();
}
// To alias a type pack use TypePack<T1,T2..,Tn>
using CharIntPack = TypePack<char,int>;
int main() {
fn<char,char>(); // invokes FN_A
fn<char,int>(); // invokes FN_B
fn<CharIntPack>(); // invokes FN_C which then invokes FN_B
return 0;
}
这会产生以下输出:
Generic
Specialized for char,int
Forwarding a pack alias
Specialized for char,int
我喜欢这种方法的是,在定义函数时只需要一次“技巧”,用户可能完全不知道它。
答案 1 :(得分:1)
参数包必须是几个类型的列表。可以通过在其上使用...运算符来转发参数包(一旦有了参数包),从而将其重新扩展回列表,但您必须从这些类型开始。
请注意: 使用MyType = std :: tuple():: type; 因为元组没有“类型”成员,所以不会起作用。你甚至不能做(有或没有...): 模板 结构持有人 { typedef类型...类型; }; 使用my_type = holder :: type;
答案 2 :(得分:1)
在下面的示例中,我试图为模板参数包添加别名 基本上
这在标准中是不可能的,所以我发现人们可以解决这个问题 使用元组或空模板结构进行限制。
float widthRatio = bitmap.getWidth() / pageSize.getWidth();
float heightRatio = bitmap.getHeight() / pageSize.getHeight();
scaleDownRatio = (widthRatio<heightRatio)? widthratio:heightRatio;
非常适合处理别名参数包!
然而我的情况似乎有所不同,因为我没有争论 参数类型包匹配...
嗯,这些情况下你发现 class-templates 实际上比 function-templates 更强大 - 在这种情况下,我们可以拥有部分模板专业化;因此,如果您决定使用带有重载std::tuple<...>
的类模板,我确实说,它可能:
Demo:
operator ()
输出:
template<typename... A>
struct fn
{
void operator () () const
{ std::cout << "primary f()" << std::endl; }
};
template<typename... A>
struct fn<std::tuple<A...>>
{
void operator () () const
{ std::cout << "specialized on unlimited params()" << std::endl; }
};
template<>
struct fn<std::tuple<char, double*>>
{
void operator () () const
{ std::cout << "specialized on f<char, double*>()" << std::endl; }
};
template<typename A, typename B>
struct fn<std::tuple<A, B>>
{
void operator () () const
{ std::cout << "specialized on two params f()" << std::endl; }
};
// Can't seem to define this correctly.
using MyType = std::tuple<int, char>;
using MyType2 = std::tuple<char, double*>;
using MyType3 = std::tuple<int, char, double, void*>;
int main()
{
fn<int, char>()();
fn<MyType>()();
fn<MyType2>()();
fn<MyType3>()();
return 0;
}
答案 3 :(得分:0)
从C ++ 14开始,如果您不想重载或重写函数,也不想编写仿函数类模板,可以使用泛型lambda将类型列表本地转换为参数包:
template<typename T>
struct quote{ using type = T; };
template<typename T>
using unpack = typename T::type;
template<typename... T>
using params = std::tuple<quote<T>...>;
// to be used as
template<typename A, typename B>
void foo();
using my_params = params<int,char>;
int main()
{
std::apply( []( auto... params ){ foo< unpack<decltype(params)>... >(); }, my_params{} );
}
PS: std::apply
需要C ++ 17,但也可以在&gt; = C ++ 11中实现......
PPS:在C ++ 20中,我们甚至可以编写[]<typename... T>(){ foo<T...>(); }
使解决方案更清晰......