Can I use a locally declared enumeration class as a non-type template parameter? (gcc gives an obscure error)

The following code is not compiled in gcc 4.8.1 through 6.3:

#include <cassert>

template<typename T, T X>
struct Mode {
    using type = Mode;
    using value_type = T;
    static constexpr value_type value = X;
^^^ error: 'constexpr const value_type Mode<main()::TestEnum, (main::TestEnum)0>::value', declared using local type 'const value_type {aka const main()::TestEnum}', is used but never defined [-fpermissive]
    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 and MSVC 2015 SP3 compile it without errors.

If I move enum class TestEnum { test1, test2 };to a global scope, then it compiles without errors.

Is the code legal? or am i doing something wrong?

+4
source share
1 answer

I think the problem is that you still need to determine Mode::valuewhat the compiler (ODR) says. If I'm not mistaken, this changes from C ++ 17, and the definition is no longer mandatory, which explains why it works with the flag std=c++1z.

"before" 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);
}

.

+2

Source: https://habr.com/ru/post/1670224/


All Articles