[英]Type alias a template parameter pack
在下面的示例中,我嘗試基本上對模板參數包進行別名。
在標准中這是不可能的,因此我發現人們使用元組或空模板結構來解決此限制。 但是我的情況似乎有所不同,因為我沒有參數參數類型包來匹配 ...
( 我知道這個示例看起來很愚蠢,但這是最小的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;
}
參考;
如果我們使用模板化的空結構來別名化類型包,則可以在原始函數上使用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
我喜歡這種方法的地方是,在定義函數時僅需要一次“ 技巧 ”,而用戶可能完全不知道它。
參數包必須就是這樣,它是幾種類型的列表。 可以通過在其上使用...運算符來轉發參數包(一旦擁有一個參數包),從而將其重新擴展回列表中,但是您必須首先使用這些類型。
並注意:使用MyType = std :: tuple():: type; 無法工作,因為元組沒有“類型”成員。 您甚至無法做到(帶有或不帶有...):template struct owner {typedef Types ... type; }; 使用my_type = holder :: type;
在下面的示例中,我嘗試基本上對模板參數包進行別名。
在標准中這是不可能的,因此我發現人們使用元組或空模板結構來解決此限制。
std::tuple<...>
非常適合為參數包加別名!
但是我的情況似乎有所不同,因為我沒有要匹配的參數參數類型包...
好吧,在這些情況下,您發現類模板實際上比功能模板更強大-在這種情況下,我們可以進行部分模板專業化 ; 因此,如果您決定使用帶有重載的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;
}
輸出:
primary f()
specialized on two params f()
specialized on f<char, double*>()
specialized on unlimited params()
從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...>(); }
[]<typename... T>(){ foo<T...>(); }
使該解決方案更干凈......
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.