static_assert 始终在 constexpr 中触发
static_assert always triggering in constexpr
我编写了以下代码来查找包含给定类型的元组中的第一个索引。
#include <cstdio>
#include <tuple>
#include <type_traits>
#include <utility>
namespace detail {
template <typename T, typename Tuple, std::size_t H, std::size_t... I>
constexpr std::size_t tuple_type_index_impl(Tuple tup, std::index_sequence<H, I...> seq, std::size_t ret = 0) {
if (std::is_same<T, typename std::tuple_element<H, Tuple>::type>::value)
ret = H;
else ret = tuple_type_index_impl<T>(tup, std::index_sequence<I...>{});
return ret;
}
template <typename T, typename Tuple, std::size_t H>
constexpr std::size_t tuple_type_index_impl(Tuple tup, std::index_sequence<H> seq) {
static_assert(std::is_same<T, typename std::tuple_element<H, Tuple>::type>::value, "type not in tuple!");
return H;
}
}
template <typename T, typename Tuple>
constexpr std::size_t tuple_type_index(Tuple tup) {
return detail::tuple_type_index_impl<T>(tup, std::make_index_sequence<std::tuple_size<Tuple>::value>{});
}
class a {};
class b {};
class c {};
class d {};
std::tuple<a, b, c> abc;
int main() {
printf("b is index : %zu\n", tuple_type_index<d>(abc));
system("pause");
return 0;
}
我遇到的问题是,如果您尝试查找任何类型的索引,但 c
将触发 static_assert
。我什至不确定为什么当您尝试查找类型 a
或 b
.
的索引时它会一直走到结束函数
如果删除 static_assert
,return 值是正确的,但它将 return 为不在元组中的类型的值。
受标记答案的启发,我修改了我的实现。
此版本应该可以在 clang++ 和 g++ 上运行,而不仅仅是在 MSVC 上运行。
我想问题是你没有写正确的终端(索引序列为空)tuple_type_index_impl()
函数。
En passant,0
值(在 "type not found" 的情况下)不是一个好主意(恕我直言),因为您可能会与 "first type".
混淆
我已经在下面修改了你的例子
#include <tuple>
#include <utility>
#include <iostream>
#include <type_traits>
namespace detail
{
template <typename T, typename Tuple>
constexpr std::size_t tuple_type_index_impl
(const Tuple &,
const std::index_sequence<> &,
std::size_t ret = std::tuple_size<Tuple>::value)
{ return ret; }
template <typename T, typename Tuple, std::size_t H, std::size_t ... I>
constexpr std::size_t tuple_type_index_impl
(const Tuple & tup,
const std::index_sequence<H, I...> & seq,
std::size_t ret = std::tuple_size<Tuple>::value)
{
return std::is_same<T, typename std::tuple_element<H, Tuple>::type>::value
? H
: tuple_type_index_impl<T>(tup, std::index_sequence<I...>{}, ret);
}
}
template <typename T, typename Tuple>
constexpr std::size_t tuple_type_index (const Tuple & tup)
{
return detail::tuple_type_index_impl<T>
(tup, std::make_index_sequence<std::tuple_size<Tuple>::value>{});
}
class a {};
class b {};
class c {};
class d {};
int main()
{
std::tuple<a, b, c> abc;
std::cout << "a is index: " << tuple_type_index<a>(abc) << std::endl;
std::cout << "b is index: " << tuple_type_index<b>(abc) << std::endl;
std::cout << "c is index: " << tuple_type_index<c>(abc) << std::endl;
std::cout << "d is index: " << tuple_type_index<d>(abc) << std::endl;
return 0;
}
给我一些时间,我试着准备一个更简单的例子。
--- 编辑:添加示例 ---
您正在使用类型,因此不需要创建和传递给函数元组(和索引序列)对象。
我已经准备了一个基于(基于 SFINAE)tupleTypeIndexHelper
结构的示例;仅使用类型,因此您使用 as
tuple_type_index<a, std::tuple<a, b, c>>()
或(当 abc
是 std::tuple<a, b, c>
的实例时)如
tuple_type_index<b, decltype(abc)>()
以下示例也适用于 C++11(至少:使用 g++ 4.9.2 和 clang++ 3.5)
#include <tuple>
#include <utility>
#include <iostream>
#include <type_traits>
namespace detail
{
template <typename T, typename Tuple, std::size_t Ind>
struct tupleTypeIndexHelper
{
static constexpr std::size_t dimT { std::tuple_size<Tuple>::value };
template <std::size_t I = Ind>
static typename std::enable_if<(I >= dimT), std::size_t>::type func ()
{ return dimT; }
template <std::size_t I = Ind>
static typename std::enable_if<(I < dimT), std::size_t>::type func ()
{
using typeI = typename std::tuple_element<I, Tuple>::type;
return std::is_same<T, typeI>::value
? I
: tupleTypeIndexHelper<T, Tuple, I+1U>::func();
}
};
}
template <typename T, typename Tuple>
constexpr std::size_t tuple_type_index ()
{ return detail::tupleTypeIndexHelper<T, Tuple, 0U>::func(); }
class a {};
class b {};
class c {};
class d {};
int main()
{
using t3 = std::tuple<a, b, c>;
std::cout << "a is index: " << tuple_type_index<a, t3>() << std::endl;
std::cout << "b is index: " << tuple_type_index<b, t3>() << std::endl;
std::cout << "c is index: " << tuple_type_index<c, t3>() << std::endl;
std::cout << "d is index: " << tuple_type_index<d, t3>() << std::endl;
std::cout << "int is index: " << tuple_type_index<int, t3>() << std::endl;
std::tuple<a, b, c> abc;
std::cout << "a is index: " << tuple_type_index<a, decltype(abc)>() << std::endl;
std::cout << "b is index: " << tuple_type_index<b, decltype(abc)>() << std::endl;
std::cout << "c is index: " << tuple_type_index<c, decltype(abc)>() << std::endl;
std::cout << "d is index: " << tuple_type_index<d, decltype(abc)>() << std::endl;
return 0;
}
我编写了以下代码来查找包含给定类型的元组中的第一个索引。
#include <cstdio>
#include <tuple>
#include <type_traits>
#include <utility>
namespace detail {
template <typename T, typename Tuple, std::size_t H, std::size_t... I>
constexpr std::size_t tuple_type_index_impl(Tuple tup, std::index_sequence<H, I...> seq, std::size_t ret = 0) {
if (std::is_same<T, typename std::tuple_element<H, Tuple>::type>::value)
ret = H;
else ret = tuple_type_index_impl<T>(tup, std::index_sequence<I...>{});
return ret;
}
template <typename T, typename Tuple, std::size_t H>
constexpr std::size_t tuple_type_index_impl(Tuple tup, std::index_sequence<H> seq) {
static_assert(std::is_same<T, typename std::tuple_element<H, Tuple>::type>::value, "type not in tuple!");
return H;
}
}
template <typename T, typename Tuple>
constexpr std::size_t tuple_type_index(Tuple tup) {
return detail::tuple_type_index_impl<T>(tup, std::make_index_sequence<std::tuple_size<Tuple>::value>{});
}
class a {};
class b {};
class c {};
class d {};
std::tuple<a, b, c> abc;
int main() {
printf("b is index : %zu\n", tuple_type_index<d>(abc));
system("pause");
return 0;
}
我遇到的问题是,如果您尝试查找任何类型的索引,但 c
将触发 static_assert
。我什至不确定为什么当您尝试查找类型 a
或 b
.
如果删除 static_assert
,return 值是正确的,但它将 return 为不在元组中的类型的值。
受标记答案的启发,我修改了我的实现。
此版本应该可以在 clang++ 和 g++ 上运行,而不仅仅是在 MSVC 上运行。
我想问题是你没有写正确的终端(索引序列为空)tuple_type_index_impl()
函数。
En passant,0
值(在 "type not found" 的情况下)不是一个好主意(恕我直言),因为您可能会与 "first type".
我已经在下面修改了你的例子
#include <tuple>
#include <utility>
#include <iostream>
#include <type_traits>
namespace detail
{
template <typename T, typename Tuple>
constexpr std::size_t tuple_type_index_impl
(const Tuple &,
const std::index_sequence<> &,
std::size_t ret = std::tuple_size<Tuple>::value)
{ return ret; }
template <typename T, typename Tuple, std::size_t H, std::size_t ... I>
constexpr std::size_t tuple_type_index_impl
(const Tuple & tup,
const std::index_sequence<H, I...> & seq,
std::size_t ret = std::tuple_size<Tuple>::value)
{
return std::is_same<T, typename std::tuple_element<H, Tuple>::type>::value
? H
: tuple_type_index_impl<T>(tup, std::index_sequence<I...>{}, ret);
}
}
template <typename T, typename Tuple>
constexpr std::size_t tuple_type_index (const Tuple & tup)
{
return detail::tuple_type_index_impl<T>
(tup, std::make_index_sequence<std::tuple_size<Tuple>::value>{});
}
class a {};
class b {};
class c {};
class d {};
int main()
{
std::tuple<a, b, c> abc;
std::cout << "a is index: " << tuple_type_index<a>(abc) << std::endl;
std::cout << "b is index: " << tuple_type_index<b>(abc) << std::endl;
std::cout << "c is index: " << tuple_type_index<c>(abc) << std::endl;
std::cout << "d is index: " << tuple_type_index<d>(abc) << std::endl;
return 0;
}
给我一些时间,我试着准备一个更简单的例子。
--- 编辑:添加示例 ---
您正在使用类型,因此不需要创建和传递给函数元组(和索引序列)对象。
我已经准备了一个基于(基于 SFINAE)tupleTypeIndexHelper
结构的示例;仅使用类型,因此您使用 as
tuple_type_index<a, std::tuple<a, b, c>>()
或(当 abc
是 std::tuple<a, b, c>
的实例时)如
tuple_type_index<b, decltype(abc)>()
以下示例也适用于 C++11(至少:使用 g++ 4.9.2 和 clang++ 3.5)
#include <tuple>
#include <utility>
#include <iostream>
#include <type_traits>
namespace detail
{
template <typename T, typename Tuple, std::size_t Ind>
struct tupleTypeIndexHelper
{
static constexpr std::size_t dimT { std::tuple_size<Tuple>::value };
template <std::size_t I = Ind>
static typename std::enable_if<(I >= dimT), std::size_t>::type func ()
{ return dimT; }
template <std::size_t I = Ind>
static typename std::enable_if<(I < dimT), std::size_t>::type func ()
{
using typeI = typename std::tuple_element<I, Tuple>::type;
return std::is_same<T, typeI>::value
? I
: tupleTypeIndexHelper<T, Tuple, I+1U>::func();
}
};
}
template <typename T, typename Tuple>
constexpr std::size_t tuple_type_index ()
{ return detail::tupleTypeIndexHelper<T, Tuple, 0U>::func(); }
class a {};
class b {};
class c {};
class d {};
int main()
{
using t3 = std::tuple<a, b, c>;
std::cout << "a is index: " << tuple_type_index<a, t3>() << std::endl;
std::cout << "b is index: " << tuple_type_index<b, t3>() << std::endl;
std::cout << "c is index: " << tuple_type_index<c, t3>() << std::endl;
std::cout << "d is index: " << tuple_type_index<d, t3>() << std::endl;
std::cout << "int is index: " << tuple_type_index<int, t3>() << std::endl;
std::tuple<a, b, c> abc;
std::cout << "a is index: " << tuple_type_index<a, decltype(abc)>() << std::endl;
std::cout << "b is index: " << tuple_type_index<b, decltype(abc)>() << std::endl;
std::cout << "c is index: " << tuple_type_index<c, decltype(abc)>() << std::endl;
std::cout << "d is index: " << tuple_type_index<d, decltype(abc)>() << std::endl;
return 0;
}