#c #c 17 #metaprogramming #constexpr #c 20
#c #c 17 #метапрограммирование #constexpr #c 20
Вопрос:
У меня есть constexpr_sequence
класс, который возвращает новое значение при каждом next()
вызове и текущее значение при value()
вызове в зависимости от функции и начального значения, заданного в качестве параметров шаблона. Например:
template<typename T, T INC>
constexpr T increase(T val)
{
return val INC;
}
using counter = qx::constexpr_sequence<struct Tag, int, 0, increase<int, 1>>;
static_assert(counter::value() == 0);
static_assert(counter::next() == 1);
static_assert(counter::value() == 1);
static_assert(counter::value() == 1);
static_assert(counter::next() == 2);
static_assert(counter::value() == 2);
static_assert(counter::next() == 3);
static_assert(counter::value() == 3);
Этот код отлично работает с MSVC, Clang, Apple Clang и GCC, а также с C 17, но тесты для MSVC завершаются неудачно, когда я включаю C 20 ( counter::value()
всегда возвращает 0, несмотря на то, что counter::next()
DO изменяет соответствующий флаг.
Код класса:
template <class Tag, typename T, T Start, T Func(T)>
class constexpr_sequence
{
private:
template <T nIndex>
struct Element
{
static constexpr T value(void) noexcept
{
T _value = Start;
for (std::size_t i = 0; i < nIndex; i )
_value = Func(_value);
return _value;
}
};
template<std::size_t nCurrent, bool bWasSetted /* = false */>
struct CheckerSetter
{
static constexpr std::size_t index(void) noexcept
{
return nCurrent;
}
};
template<T nCurrent>
struct CheckerWrapper
{
template<bool bWasSetted = constexpr_flag<Element<nCurrent>>{}.test(),
std::size_t nNext = CheckerSetter<nCurrent, bWasSetted>{}.index()>
static constexpr std::size_t index(void) noexcept
{
return nNext;
}
};
template<std::size_t nCurrent>
struct CheckerSetter<nCurrent, /* bool bWasSetted = */ true>
{
template<std::size_t nNext = CheckerWrapper<nCurrent 1>{}.index()>
static constexpr std::size_t index(void) noexcept
{
return nNext;
}
};
public:
template <std::size_t nIndex = CheckerWrapper<0>{}.index(),
T _value = Element<nIndex>{}.value()>
static constexpr T value(void) noexcept
{
return _value;
}
template <std::size_t nIndex = CheckerWrapper<0>{}.index(),
T _value = Element<nIndex>{}.value(),
bool bStub = constexpr_flag<Element<nIndex>>{}.test_and_set()>
static constexpr T next(void) noexcept
{
return Func(_value);
}
};
Класс имеет мой constexpr_flag
класс как зависимость, этот класс возвращает «Start» в начале ( test()
), «Start» с test_and_set
и «End» после test()
. Тесты для этого кода проходят успешно, но вы можете проверить это, если считаете, что проблема именно здесь.
репо:
constexpr_flag
constexpr_sequence
test_constexpr_flag
тест_constexpr_sequence
Чтобы воспроизвести проблему:
git clone https://github.com/n0lavar/qxLib.git
open qxLibcmakeplatform_options.cmake, change cxx_std_17 to cxx_std_20
git clone https://github.com/google/googletest.git
cd googletest
mkdir build
cd build
cmake ..
cmake --build .
cd ..
cd ..
cd qxLib
mkdir build
cd build
cmake -DGENERATE_TESTS=1 ..
cmake --build .
сборка завершится ошибкой с test_constexpr_sequence
(и зависит от них test_constexpr_random
и test_rtti
)
Вопросы:
Почему этот код не работает?
Правильно ли поведение MSVC (было бы здорово увидеть ссылки на стандарт)?
Какие изменения мне нужно внести, чтобы исправить это?
Комментарии:
1. Для меня это
constexpr_sequence
подозрительно. Как он должен работать, если он используется в нескольких единицах перевода?2. Он был разработан для целей идентификаторов классов, он отлично работал для меня с c 17. В любом случае, ваш вопрос не о реальной проблеме
3. Почему этот код не работает? Правильно ли поведение MSVC (было бы здорово увидеть ссылки на стандарт)? Какие изменения мне нужно внести, чтобы исправить это? — Может быть, компилятор сломан? Если компилятор продемонстрировал такое поведение, не следует ли первым делом перейти на сайт Microsoft и показать им свои результаты? Я уверен, что инженеры там исправят (если сломано) как можно скорее. Если компилятор сломан, они были бы теми, кто мог бы это исправить — никто здесь не смог бы этого сделать.
4. Ошибка, о которой сообщается как о возможной ошибке компилятора developercommunity.visualstudio.com/content/problem/1300886 /…