1

在下面的示例中,我试图基本上别名模板参数包。键入别名模板参数包

这在标准中是不可能的,所以我发现人们用元组或空的模板结构来解决限制。但是我的情况似乎有所不同,因为我没有一个参数参数类型包匹配 ...

我知道这个样品看起来很蠢,但它是一个最小的PoC,在代码库类型串变长了不少这真的很有用。

#include <iostream> 
#include <tuple> 

template<typename T> 
void f(T t) 
{ 
    std::cout << "templated f()" << std::endl; 

} 
template<> 
void f(int t) 
{ 
    std::cout << "specialized f()" << std::endl; 
} 

template<typename A, typename B> 
void fn() 
{ 
    f(A()); 
} 

template<int, char> 
void fn() 
{ 
    int a; 
    f(a); 
} 

// Can't seem to define this correctly. 
//using MyType = std::tuple<int, char>()::type; 

int 
main(int, char**) 
{ 
    fn<char, char>(); 

    // I have 
    fn<int, char>(); 

    // I want some alias; 
    //fn<MyType>(); 

    return 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

的参数组必须是公正的,几种类型的列表。可以通过使用...操作符来转发参数包(一旦有参数包),从而将参数包重新扩展为列表,但必须具有这些类型。使用MyType = std :: tuple():: type;注意: 不会工作,因为元组没有'type'成员。你甚至不能这样做(有或没有......): template struct holder { typedef Types ... type; }; using my_type = holder :: type;

1

在下面的示例中,我试图给别名模板参数包 基本上。

这在标准中是不可能的,所以我发现人们用 限制了一个元组或空的模板结构。

std::tuple<...>做混叠参数包是伟大的!

然而,我的情况似乎不同,因为我没有参数 参数类型包匹配...

那么,这些在那里你会发现,类模板实际上比函数模板更强大的一个案例 - 在这种情况下,我们可以有部分模板特;所以,如果你决定使用一个类模板与超载operator(),我也确实讲过,它可能:

Demo

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; 
} 

输出:

primary f() 
specialized on two params f() 
specialized on f<char, double*>() 
specialized on unlimited params() 
+0

谢谢,这是一个很好的解决方案我只是不喜欢函子所需的接口,如果他们不是自由职守但是类成员。你有'object :: fn()'而不是'object.fn()'。 – dzan

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,而是可以以> = C++ 11以及被实现...

PPS:在C++ 20,我们甚至可以写[]<typename... T>(){ foo<T...>(); }使该解决方案更清洁......