c – 我可以使用本地声明的枚举类作为模板非类型参数吗? (gcc给出了不明确的错误)

以下代码无法在
gcc 4.8.1到6.3中编译:

#include <cassert>

template<typename T, T X>
struct Mode {
    using type = Mode;
    using value_type = T;
    static constexpr value_type value = X;

06001

    constexpr operator value_type() const noexcept { return value; }
};

int main()
{
    enum class TestEnum { test1, test2 };
    constexpr Mode<TestEnum, TestEnum::test1> test1 = {};
    constexpr Mode<TestEnum, TestEnum::test2> test2 = {};

    assert(static_cast<TestEnum>(test1) == TestEnum::test1);
}

clang 3.9.1和MSVC 2015 SP3编译它没有错误.

如果我移动枚举类TestEnum {test1,test2};进入全局范围然后编译没有错误.

代码合法吗?或者我做错了什么?

最佳答案 我认为问题是,您仍然需要定义Mode :: value,正如编译器所说(ODR).如果我没有弄错的话,这会随着C 17而改变,并且定义不再是强制性的,这就解释了为什么它与std = c 1z标志一起运行.

这也编译并运行“之前”std = c 1z:

#include <cassert>

template<typename T, T X>
struct Mode {
    using type = Mode;
    using value_type = T;
    static constexpr value_type value = X;

    constexpr operator value_type() const noexcept { return value; }
};

template<typename T, T X> constexpr T Mode<T,X>::value;

int main()
{
    enum class TestEnum { test1, test2 };
    constexpr Mode<TestEnum, TestEnum::test1> test1 = {};
    //constexpr Mode<TestEnum, TestEnum::test2> test2 = {};

    assert(static_cast<TestEnum>(test1) == TestEnum::test1);
}

你可以see it live.

点赞