如何使用 C++14 和 C++1z 中的功能缩短此可变参数模板代码?
How can I make this variadic template code shorter using features from C++14 and C++1z?
这是一个代码片段,我将使用它来检查可变参数模板类型是否唯一:
template <typename...>
struct is_one_of;
template <typename F>
struct is_one_of<F> {
static constexpr bool value = false;
};
template <typename F, typename S, typename... T>
struct is_one_of<F, S, T...> {
static constexpr bool value =
std::is_same<F, S>::value || is_one_of<F, T...>::value;
};
template <typename...>
struct is_unique;
template <>
struct is_unique<> {
static constexpr bool value = true;
};
template <typename F, typename... T>
struct is_unique<F, T...> {
static constexpr bool value =
is_unique<T...>::value && !is_one_of<F, T...>::value;
};
int main() {
constexpr bool b = is_unique<bool, int, double>::value;
constexpr bool c = is_unique<int, char, int>::value;
static_assert(b == true && c == false, "!");
}
有什么方法可以使用 C++14 和 C++1z 中引入的功能使此代码更短 and/or 更简洁?或者有没有更好的方法来使用新功能达到相同的效果?
对于 C++1z,我的意思是:最新版本的 Clang 和 GCC 中已经提供的功能。
我(现在)建议使用 std::conj/disj/nega
系列的 STL 函数:
#include <type_traits>
template <typename H, typename... T>
struct is_one_of : std::disjunction<std::is_same<H, T>...> {};
template <typename H, typename... T>
struct is_unique : std::conjunction<std::negation<std::is_same<H, T>>..., is_unique<T...>> {};
template <typename H>
struct is_unique<H> : std::true_type {};
int main()
{
static_assert(is_one_of<int, char, double, int, bool>::value);
static_assert(is_unique<int, char, double, bool>::value);
static_assert(!is_unique<int, int, char, double, bool>::value);
}
当为这些情况设计的 fold-expressions 被发布到语言中时,这将变得微不足道:
namespace stx = std::experimental;
template <typename H, typename... T>
struct is_one_of {
static constexpr bool value = (stx::is_same_v<H, T> || ...);
};
template <typename H, typename... T>
struct is_unique {
static constexpr bool value = (!stx::is_same_v<H, T> && ... && is_unique<T...>::value);
};
template <typename H>
struct is_unique<H> : std::true_type {};
就折叠表达式部分而言,我与 Brian Rodriguez 和 Piotr Scontnincki 的回答一致。在折叠表达式出现之前,您可以通过删除不完整的主模板来稍微缩减现有代码,如下所示:
template <typename...>
struct is_one_of {
static constexpr bool value = false;
};
template <typename F, typename S, typename... T>
struct is_one_of<F, S, T...> {
static constexpr bool value =
std::is_same<F, S>::value || is_one_of<F, T...>::value;
};
template <typename...>
struct is_unique {
static constexpr bool value = true;
};
template <typename F, typename... T>
struct is_unique<F, T...> {
static constexpr bool value = is_unique<T...>::value && !is_one_of<F, T...>::value;
};
#include <type_traits>
template <typename F, typename... Ts>
constexpr bool is_one_of = (std::is_same<F, Ts>{} || ...);
template <typename...>
constexpr bool is_unique = true;
template <typename F, typename... Ts>
constexpr bool is_unique<F, Ts...> = is_unique<Ts...> && !is_one_of<F, Ts...>;
我们最近在 C++1z 草案中添加了 std::disjunction,它可以用于 is_one_of
(并且一旦找到匹配就停止实例化,参见 link了解更多详情):
template <typename F, typename... T>
using is_one_of = std::disjunction<is_same<F, T>...>;
这已经在 GCC 主干中实现。对于旧版本的 GCC,您可以使用实现细节 __or_
代替:
template <typename F, typename... T>
using is_one_of = std::__or_<is_same<F, T>...>;
或使用 C++11 工具手动实现 disjunction
,如提案末尾所示 linked to above。
这是一个代码片段,我将使用它来检查可变参数模板类型是否唯一:
template <typename...>
struct is_one_of;
template <typename F>
struct is_one_of<F> {
static constexpr bool value = false;
};
template <typename F, typename S, typename... T>
struct is_one_of<F, S, T...> {
static constexpr bool value =
std::is_same<F, S>::value || is_one_of<F, T...>::value;
};
template <typename...>
struct is_unique;
template <>
struct is_unique<> {
static constexpr bool value = true;
};
template <typename F, typename... T>
struct is_unique<F, T...> {
static constexpr bool value =
is_unique<T...>::value && !is_one_of<F, T...>::value;
};
int main() {
constexpr bool b = is_unique<bool, int, double>::value;
constexpr bool c = is_unique<int, char, int>::value;
static_assert(b == true && c == false, "!");
}
有什么方法可以使用 C++14 和 C++1z 中引入的功能使此代码更短 and/or 更简洁?或者有没有更好的方法来使用新功能达到相同的效果?
对于 C++1z,我的意思是:最新版本的 Clang 和 GCC 中已经提供的功能。
我(现在)建议使用 std::conj/disj/nega
系列的 STL 函数:
#include <type_traits>
template <typename H, typename... T>
struct is_one_of : std::disjunction<std::is_same<H, T>...> {};
template <typename H, typename... T>
struct is_unique : std::conjunction<std::negation<std::is_same<H, T>>..., is_unique<T...>> {};
template <typename H>
struct is_unique<H> : std::true_type {};
int main()
{
static_assert(is_one_of<int, char, double, int, bool>::value);
static_assert(is_unique<int, char, double, bool>::value);
static_assert(!is_unique<int, int, char, double, bool>::value);
}
当为这些情况设计的 fold-expressions 被发布到语言中时,这将变得微不足道:
namespace stx = std::experimental;
template <typename H, typename... T>
struct is_one_of {
static constexpr bool value = (stx::is_same_v<H, T> || ...);
};
template <typename H, typename... T>
struct is_unique {
static constexpr bool value = (!stx::is_same_v<H, T> && ... && is_unique<T...>::value);
};
template <typename H>
struct is_unique<H> : std::true_type {};
就折叠表达式部分而言,我与 Brian Rodriguez 和 Piotr Scontnincki 的回答一致。在折叠表达式出现之前,您可以通过删除不完整的主模板来稍微缩减现有代码,如下所示:
template <typename...>
struct is_one_of {
static constexpr bool value = false;
};
template <typename F, typename S, typename... T>
struct is_one_of<F, S, T...> {
static constexpr bool value =
std::is_same<F, S>::value || is_one_of<F, T...>::value;
};
template <typename...>
struct is_unique {
static constexpr bool value = true;
};
template <typename F, typename... T>
struct is_unique<F, T...> {
static constexpr bool value = is_unique<T...>::value && !is_one_of<F, T...>::value;
};
#include <type_traits>
template <typename F, typename... Ts>
constexpr bool is_one_of = (std::is_same<F, Ts>{} || ...);
template <typename...>
constexpr bool is_unique = true;
template <typename F, typename... Ts>
constexpr bool is_unique<F, Ts...> = is_unique<Ts...> && !is_one_of<F, Ts...>;
我们最近在 C++1z 草案中添加了 std::disjunction,它可以用于 is_one_of
(并且一旦找到匹配就停止实例化,参见 link了解更多详情):
template <typename F, typename... T>
using is_one_of = std::disjunction<is_same<F, T>...>;
这已经在 GCC 主干中实现。对于旧版本的 GCC,您可以使用实现细节 __or_
代替:
template <typename F, typename... T>
using is_one_of = std::__or_<is_same<F, T>...>;
或使用 C++11 工具手动实现 disjunction
,如提案末尾所示 linked to above。