如何根据类型特征进行 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();