如何根据类型特征进行 constexpr 计数
How to do a constexpr count based on a type trait
我有一个对象数据库,想在编译时计算特定类型的对象数量,但我在编译时遇到了一些麻烦。
这是我到目前为止一直在尝试的简化示例,但是无法使用 "error: call to function 'do_count' that is neither visible in the template definition nor found by argument-dependent lookup"
进行编译
有没有更好的方法?
#include <cstdint>
#include <type_traits>
#include <cstddef>
struct unused_tag {};
struct used_tag {};
template<std::size_t X>
struct traits {
using type = unused_tag;
};
template<>
struct traits<7> {
using type = used_tag;
};
static constexpr const std::size_t MAX_X = 10;
template<std::size_t X = 0>
constexpr
std::enable_if_t<
!std::is_same<typename traits<X>::type, unused_tag>::value,
std::size_t>
do_count()
{
return do_count<X + 1>() + 1;
}
template<std::size_t X = 0>
constexpr
std::enable_if_t<
std::is_same<typename traits<X>::type, unused_tag>::value,
std::size_t>
do_count()
{
return do_count<X + 1>();
}
template<>
constexpr std::size_t do_count<MAX_X>()
{
return 0;
}
static constexpr const std::size_t COUNT = do_count();
原来我太聪明了,这很简单:
#include <cstdint>
#include <type_traits>
#include <cstddef>
struct unused_tag {};
struct used_tag {};
template<std::size_t X>
struct traits {
using type = unused_tag;
};
template<>
struct traits<7> {
using type = used_tag;
};
static constexpr const std::size_t MAX_COUNT = 10;
template<std::size_t X = 0>
constexpr std::size_t do_count()
{
if (std::is_same<typename traits<X>::type, unused_tag>::value)
return 0 + do_count<X + 1>();
return 1 + do_count<X + 1>();
}
template<>
constexpr std::size_t do_count<MAX_COUNT>()
{
return 0;
}
static constexpr const std::size_t COUNT = do_count();
static_assert(COUNT == 1);
您似乎找到了解决问题的不同方法,但如果您好奇的话,这里有一个使用 std::enable_if 的解决方案。
问题是从 !std::is_same<...> 版本调用 do_count 看不到 std::is_same<...> 版本,因为您的编译器说,从呼叫站点看不到它,无法解决。要解决此问题,只需对 std::is_same<...>.
进行前向声明
对于您的示例,以下为我编译:
#include <cstdint>
#include <type_traits>
#include <cstddef>
struct unused_tag {};
struct used_tag {};
template<std::size_t X>
struct traits {
using type = unused_tag;
};
template<>
struct traits<9> {
using type = used_tag;
};
static constexpr const std::size_t MAX_X = 10;
//
// forward declaration
//
template<std::size_t X = 0>
constexpr
std::enable_if_t<
std::is_same<typename traits<X>::type, unused_tag>::value,
std::size_t>
do_count();
template<std::size_t X = 0>
constexpr
std::enable_if_t<
!std::is_same<typename traits<X>::type, unused_tag>::value,
std::size_t>
do_count()
{
return do_count<X + 1>() + 1;
}
template<std::size_t X>
constexpr
std::enable_if_t<
std::is_same<typename traits<X>::type, unused_tag>::value,
std::size_t>
do_count()
{
return do_count<X + 1>();
}
template<>
constexpr std::size_t do_count<MAX_X>()
{
return 0;
}
static constexpr const std::size_t COUNT = do_count();
我有一个对象数据库,想在编译时计算特定类型的对象数量,但我在编译时遇到了一些麻烦。
这是我到目前为止一直在尝试的简化示例,但是无法使用 "error: call to function 'do_count' that is neither visible in the template definition nor found by argument-dependent lookup"
进行编译有没有更好的方法?
#include <cstdint>
#include <type_traits>
#include <cstddef>
struct unused_tag {};
struct used_tag {};
template<std::size_t X>
struct traits {
using type = unused_tag;
};
template<>
struct traits<7> {
using type = used_tag;
};
static constexpr const std::size_t MAX_X = 10;
template<std::size_t X = 0>
constexpr
std::enable_if_t<
!std::is_same<typename traits<X>::type, unused_tag>::value,
std::size_t>
do_count()
{
return do_count<X + 1>() + 1;
}
template<std::size_t X = 0>
constexpr
std::enable_if_t<
std::is_same<typename traits<X>::type, unused_tag>::value,
std::size_t>
do_count()
{
return do_count<X + 1>();
}
template<>
constexpr std::size_t do_count<MAX_X>()
{
return 0;
}
static constexpr const std::size_t COUNT = do_count();
原来我太聪明了,这很简单:
#include <cstdint>
#include <type_traits>
#include <cstddef>
struct unused_tag {};
struct used_tag {};
template<std::size_t X>
struct traits {
using type = unused_tag;
};
template<>
struct traits<7> {
using type = used_tag;
};
static constexpr const std::size_t MAX_COUNT = 10;
template<std::size_t X = 0>
constexpr std::size_t do_count()
{
if (std::is_same<typename traits<X>::type, unused_tag>::value)
return 0 + do_count<X + 1>();
return 1 + do_count<X + 1>();
}
template<>
constexpr std::size_t do_count<MAX_COUNT>()
{
return 0;
}
static constexpr const std::size_t COUNT = do_count();
static_assert(COUNT == 1);
您似乎找到了解决问题的不同方法,但如果您好奇的话,这里有一个使用 std::enable_if 的解决方案。
问题是从 !std::is_same<...> 版本调用 do_count 看不到 std::is_same<...> 版本,因为您的编译器说,从呼叫站点看不到它,无法解决。要解决此问题,只需对 std::is_same<...>.
进行前向声明对于您的示例,以下为我编译:
#include <cstdint>
#include <type_traits>
#include <cstddef>
struct unused_tag {};
struct used_tag {};
template<std::size_t X>
struct traits {
using type = unused_tag;
};
template<>
struct traits<9> {
using type = used_tag;
};
static constexpr const std::size_t MAX_X = 10;
//
// forward declaration
//
template<std::size_t X = 0>
constexpr
std::enable_if_t<
std::is_same<typename traits<X>::type, unused_tag>::value,
std::size_t>
do_count();
template<std::size_t X = 0>
constexpr
std::enable_if_t<
!std::is_same<typename traits<X>::type, unused_tag>::value,
std::size_t>
do_count()
{
return do_count<X + 1>() + 1;
}
template<std::size_t X>
constexpr
std::enable_if_t<
std::is_same<typename traits<X>::type, unused_tag>::value,
std::size_t>
do_count()
{
return do_count<X + 1>();
}
template<>
constexpr std::size_t do_count<MAX_X>()
{
return 0;
}
static constexpr const std::size_t COUNT = do_count();