为什么 consteval 函数内的模板接受函数参数作为其模板参数之一?

Mar*_*hrs 5 c++ templates c++20 consteval

我尝试从我的代码库中提取一个最小的工作示例:

#include <concepts>

enum class unit_type
{
};

template <typename Candidate>
concept unit_c = requires()
{
    requires std::semiregular<Candidate>;
    { Candidate::type } -> std::same_as<const unit_type&>;
};

struct unit
{
    static constexpr unit_type type{};
};

template<unit_c auto unit_1, unit_c auto unit_2>
struct unit_product
{
    static constexpr unit_type type{};
};

template <unit_c Unit1, unit_c Unit2>
consteval unit_c auto operator*(Unit1 unit_1, Unit2 unit_2) noexcept
{
    return unit_product<unit_1, unit_2>{};
}

int main()
{
    constexpr unit_c auto a = unit{} * unit{};

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

上面的代码编译得很好。但为什么?我认为不能将 consteval 函数的参数传递给模板。所有的gcc、clang和msvc都接受上面的代码。

此代码会产生错误:

template <int val>
struct bla
{

};

consteval void bla_test(int val)
{
    bla<val>;
}
Run Code Online (Sandbox Code Playgroud)

这两种情况的主要区别是什么?

Art*_*yer 7

复制unit对象(使用默认的复制构造函数)实际上并不访问该对象(因为它没有成员)。因此,即使初始对象不是常量表达式,创建用作 NTTP 参数的副本也是常量unit表达式。

这与调用不访问的成员函数类似*this

unit a;
constexpr unit b = a;  // a isn't accessed

std::array<int, 5> arr;
constexpr std::size_t sz = arr.size();  // arr isn't accessed
Run Code Online (Sandbox Code Playgroud)

与此情况的主要区别在于,如果您尝试复制它,则将int访问它的值。int val