![](/img/trans.png)
[英]how to check if type 'T' has 'T(std::initializer_list<U>)' constructor
[英]How to statically check if type T of a template is std::vector<U>, where U is either float, double or integral
如何檢查參數包中的參數是否包含float
, double
, integral或std::vector
的類型?
例如T={int, long, std::vector<double>}
很好,
雖然T={int, long, std::vector<long double>}
不是,因為我們不允許std::vector
為long double
類型。
我到目前為止
template<class ...T>
void foo(T... t)
{
static_assert(std::is_same<float, T...>::value
|| std::is_same<double, T...>::value
|| std::is_integral<T...>::value
/* || std::is_same<std::vector<float/double/integral>, T>::value ? */
, "unsupported type!");
}
並不確定如何表達std::vector
的限制。
以某種方式重用float/double/integral
檢查會很好,所以我們不需要輸入兩次。 就像是
bool basic_check = std::is_same<float, T...>::value
|| std::is_same<double, T...>::value
|| std::is_integral<T...>::value;
static_assert(basic_check
|| std::is_same<std::vector<basic_check>, T>
, "unsupported type!");
我還希望斷言在T={}
時成功(即傳遞構建)。
您可以使用模板專業化創建自己的支票。 為了減少代碼的大小,我擴展了檢查以包括long double
。
#include <type_traits>
#include <vector>
template<class T>
struct is_ok {
static constexpr bool value =
std::is_floating_point<T>::value ||
std::is_integral<T>::value;
};
template<class T>
struct is_ok<std::vector<T>> {
static constexpr bool value =
std::is_floating_point<T>::value ||
std::is_integral<T>::value;
};
這是一個演示:
#include <cstdio>
#define TEST(x) \
std::printf("%s: %s\n", #x, is_ok<x>::value ? "true" : "false")
int main() {
TEST(int);
TEST(float);
TEST(char *);
TEST(std::vector<int>);
TEST(std::vector<float>);
TEST(std::vector<char *>);
return 0;
}
輸出:
int: true
float: true
char *: false
std::vector<int>: true
std::vector<float>: true
std::vector<char *>: false
首先寫一個測試一種類型的特征:
template<class T>
struct is_ok : std::is_arithmetic<T> { };
template<class T, class A>
struct is_ok<std::vector<T, A>> : std::is_arithmetic<T> { };
然后測試該特征對於包中的每種類型都適用。 我更喜歡使用bool_pack
的bool_pack
技巧:
template<bool...> class bool_pack;
template<bool... b>
using all_true = std::is_same<bool_pack<true, b...>, bool_pack<b..., true>>;
template<class ...T>
void foo(T... t)
{
static_assert( all_true<is_ok<T>::value...>::value, "unsupported type!");
}
您可以使用幫助程序類來執行您想要執行的操作。
template<class ...T> struct is_float_or_integral;
template <typename T> struct is_float_or_integral<T>
{
static const bool value =
std::is_integral<T>::value ||
std::is_floating_point<T>::value;
};
// Use this if you want vector<vector<int>> to be OK.
template <typename T> struct is_float_or_integral<std::vector<T>>
{
static const bool value = is_float_or_integral<T>::value;
};
// Use this if you don't want vector<vector<int>> to be OK.
template <typename T> struct is_float_or_integral<std::vector<T>>
{
static const bool value =
std::is_integral<T>::value ||
std::is_floating_point<T>::value;
};
template <typename T1, typename ...T> struct is_float_or_integral<T1, T...>
{
static const bool value =
is_float_or_integral<T1>::value &&
is_float_or_integral<T...>::value;
};
並將其用作:
template<class ...T>
void foo(T... t)
{
static_assert(is_float_or_integral<T...>::value == true, "Problem");
//
// ... Rest of your function.
}
函數重載允許對向量元素類型的限制稍微簡單一些,並且一個簡單的ignore
輔助函數接受參數並丟棄它們允許您輕松地為每個參數添加相關檢查:
#include <type_traits>
#include <vector>
template <typename T>
auto is_valid(T) ->
std::integral_constant<
bool,
std::is_integral<T>::value
|| std::is_same<T, float>::value
|| std::is_same<T, double>::value>;
template <typename T>
auto is_valid(std::vector<T>) ->
std::integral_constant<
bool,
std::is_integral<T>::value
|| std::is_same<T, float>::value
|| std::is_same<T, double>::value>;
void ignore(...) { }
template<class ...T>
void foo(T... t)
{
ignore([]() {
static_assert(decltype(is_valid(t))::value, "unsupported type!");
}...);
}
@Dietrich Epp和@ TC的解決方案都很好,除了第一個沒有解釋如何在我的問題中使用的可變參數模板案例中使用它,而后者沒有解釋如何將解決方案擴展到更多而不是一個約束檢查(雖然@TC后來把它放在評論中,但我已經在他評論之前使用了他們的合並解決方案)。
無論如何,這是他們合並的解決方案,如果有人有興趣。 它還重用了問題中提到的基類型限制。
// base type restrictions
template<class T>
struct is_ok_base
{
static constexpr bool value =
std::is_same<float, T>::value
|| std::is_same<double, T>::value
|| std::is_integral<T>::value;
};
// allow any types that is_ok_base accepts
template<class T>
struct is_ok
{
static constexpr bool value = is_ok_base<T>::value;
};
// allow any types for std::vector that is_ok_base accepts
template<class T>
struct is_ok<std::vector<T>>
{
// replace is_ok_base<T>::value with is_ok<T>::value if you want to allow
// nested vectors
static constexpr bool value = is_ok_base<T>::value;
};
// some boilerplate to make the checks above work with variadic templates
template<bool...> class bool_pack;
template<bool... b>
using all_true = std::is_same<bool_pack<true, b...>, bool_pack<b..., true>>;
// the actual check
template<class ...T>
constexpr void static_type_check()
{
static_assert(all_true<is_ok<T>::value...>::value, "Unsupported type!");
}
template<class ...T>
void foo(T... t)
{
static_type_check<T...>(); // or just copypaste the static_assert into here
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.