【问题标题】:How to do a constexpr count based on a type trait如何根据类型特征进行 constexpr 计数
【发布时间】:2016-12-22 03:40:34
【问题描述】:

我有一个对象数据库,想在编译时计算有多少是特定类型的,但编译时遇到了一些麻烦。

这是迄今为止我一直在尝试的一个精简示例,但这无法编译并出现“错误:调用函数'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_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();

【问题讨论】:

  • 这个“数据库”是什么样的?您能否通过一些所需输入和输出的示例提供更好的解释?该错误在哪一行?

标签: c++ constexpr enable-if


【解决方案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();

【讨论】:

    【解决方案2】:

    事实证明我太聪明了,就这么简单:

    #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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-07-13
      • 1970-01-01
      • 2017-04-12
      • 2014-02-11
      • 2014-09-21
      • 2021-01-30
      • 1970-01-01
      相关资源
      最近更新 更多