[英]How do I enable_if a struct depending on a condition and how many arguments?
我想創建一個元函數,如果將一個以上的參數傳遞給它,則返回某種類型;如果僅將一個參數傳遞給它,則根據條件返回另一種類型。 該條件是任意的,因此將需要一個enable_if
或類似類型的東西,但在本示例中,我將其enable_if
類型比較。 讓我們簡化為以下內容
int
,則返回bool
double
,則返回int
double
為此,我嘗試執行以下操作:
#include <type_traits>
template <typename Enable, typename...Args>
struct Get;
// multiple arguments; return double regardless of the condition
template <typename FirstArg, typename... OtherArgs>
struct Get<typename std::enable_if<true>::type, FirstArg, OtherArgs...>
{
using type = double;
};
// single int; return bool
template <typename Arg>
struct Get<typename std::enable_if<std::is_same<Arg, int>::value>::type, Arg>
{
using type = double;
};
// single double; return int
template <typename Arg>
struct Get<typename std::enable_if<std::is_same<Arg, double>::value>::type, Arg>
{
using type = int;
};
int main()
{
static_assert(std::is_same<typename Get<double>::type, int>::value, "");
static_assert(std::is_same<typename Get<int>::type, bool>::value, "");
static_assert(std::is_same<typename Get<bool, int>::type, double>::value, "");
return 0;
}
輸出:
prog.cpp: In function 'int main()': prog.cpp:29:51: error: 'type' in 'struct Get<double>' does not name a type static_assert(std::is_same<typename Get<double>::type, int>::value, ""); ^ prog.cpp:29:60: error: template argument 1 is invalid static_assert(std::is_same<typename Get<double>::type, int>::value, "");
我將不勝感激,因為它能教給我一個答案, 為什么它不能按我預期的方式工作,而不僅僅是如何解決它。 我正在努力尋找有關模板元編程的良好資源,到目前為止,我一直很隨意地進行編程,這是我非常想解決的問題!
該template
參數的特化不是模板參數的原始定義。
對應於原始定義的名稱位於template
名稱之后。
專業化的template<>
部分中的參數是為匹配專業化而引入的類型。
所以原來的定義:
template <typename Enable, typename...Args>
struct Get;
1個或多個類型參數。 並且,除非專業匹配,否則未定義。
第一專業化:
template <typename FirstArg, typename... OtherArgs>
struct Get<typename std::enable_if<true>::type, FirstArg, OtherArgs...> {
using type = double;
};
好吧, std::enable_if<true>::type
只是void
,因此與以下內容相同:
template <typename FirstArg, typename... OtherArgs>
struct Get<void, FirstArg, OtherArgs...> {
using type = double;
};
因此,如果第一個類型為void
,並且至少還有一個其他類型,則此匹配。
第二專業化:
template <typename Arg>
struct Get<typename std::enable_if<std::is_same<Arg, int>::value>::type, Arg> {
using type = double;
};
因此,如果有兩種類型,它將嘗試匹配。 第二個是模式匹配。
如果不是int
,則第一個SFINAE失敗。 如果它是一個int
,第一個最終被void
。 因此,這僅匹配Get<void, int>
。
第三專業化:
template <typename Arg>
struct Get<typename std::enable_if<std::is_same<Arg, double>::value>::type, Arg> {
using type = int;
};
同樣,它匹配Get<void, double>
。
專業是模式匹配。 SFINAE enable_if
子句無法進行模式匹配。 因此,運行模式匹配,然后評估enable_if
子句。 如果它們失敗,則專業化將不匹配。 如果它們成功,則enable_if
子句產生一個類型。 生成所有類型(不是模式)之后,類型的結果列表要么匹配,要么不匹配。
使用此機制的簡單方法包括將您的公共版本轉發到詳細信息,將void
作為第一種類型傳遞,並在那里進行enable_if
工作。
另一種方法是將類型捆綁為類型列表,例如template<class...>struct types{};
,並將其作為一個參數傳遞,並將void
作為第二個參數傳遞,然后對該void
再次執行SFINAE。
這是一個例子:
namespace details {
template<class...>struct types{};
template<class Types, class=void>
struct foo;
template<class T0, class... Ts>
struct foo<types<T0, Ts...>,typename std::enable_if<
std::is_same<T0, int>::value && (sizeof...(Ts)>=1)
>> {
using type=double;
};
}
template<class T0, class... Ts>
struct foo:details::foo< details::types<T0, Ts...> >{};
details::foo
模式的特殊化與types
包匹配。 它使用那些模式匹配的類型執行enable_if
邏輯。 當且僅當第一種類型為int
且存在一種或多種其他類型(用於任意測試集)時, enable_if
通過。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.