VS2017 [15.8.6] если ошибка сборки constexpr с сообщением C2760 - PullRequest
0 голосов
/ 08 октября 2018

Начиная с последней версии VS2017, этот код не работает, в то время как в предыдущем выпуске точно такая же сборка кода:

inline std::tuple<float, float> _convertCentsToAlterAndCents (float shift);

using AccidentalVar = std::variant<std::nullopt_t, int, float, double, const char*, std::string, Accidental, Accidental::Ptr>;

void Pitch::accidental(AccidentalVar value)
{
    std::visit([this](auto&& arg)
    {
        using T = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;

        if constexpr (std::is_same_v<T, int> ||
                      std::is_same_v<T, float> || 
                      std::is_same_v<T, double>)
        {
            auto [alter, cents] = _convertCentsToAlterAndCents(static_cast<float>(arg) * 100.f);
            _accidental = std::make_shared<Accidental>(alter);
            if (abs(cents) > 0.01f)
                microtone(cents);
        }
        else
        if constexpr (std::is_same_v<T, const char*> ||
                      std::is_same_v<T, std::string>)
        {
            _accidental = std::make_shared<Accidental>(arg);
        }
        else
        if constexpr (std::is_same_v<T, Accidental::Ptr>)
        {
            _accidental = (arg != nullptr) ? arg->deepcopy() : arg;
        }
        else
        if constexpr (std::is_same_v<T, Accidental>)
        {
            _accidental = arg.deepcopy();
        }
        else
        if constexpr (std::is_same_v<T, std::nullopt_t>)
        {
            _accidental = nullptr;
        }
    },
    value);
}

Ошибка C2760, unexcepted token '>' в строке if (abs(cents) > 0.01f).

Если я удаляю constexpr в if constexpr, я получаю проблему static_cast<float>, потому что arg (std::variant) может быть std::nullopt (далее обрабатывается в посетителе).

Почемупростое условие abs(cents) > 0.01f не удалось построить?

Большое спасибо за ваш ответ.

РЕДАКТИРОВАТЬ:

Может быть, моя проблема связана с этим:

constexpr

Visual Studio 2017 правильно выдает ошибку, когда левый операнд операции условной оценки недопустим в контексте constexpr.Следующий код компилируется в Visual Studio 2015, но не в Visual Studio 2017 (функция constexpr C3615 'f' не может привести к константному выражению):

template<int N>
struct array
{
    int size() const { return N; }
};

constexpr bool f(const array<1> &arr)
{
    return arr.size() == 10 || arr.size() == 11; // C3615
}

Чтобы исправить ошибку, либо объявите array :: size() работает как constexpr или удаляет квалификатор constexpr из f.

source: https://docs.microsoft.com/fr-fr/cpp/cpp-conformance-improvements-2017?view=vs-2017#bug-fixes-in-visual-studio-versions-150-153update153-155update155-157update157-and-158update158

EDIT2: Если я прокомментирую строку if (abs(cents) > 0.01f) (вызов microtone(cents) без порогового условия), код строится нормально.Таким образом, хотя 0.01f - это float constant, а cents - float temporary variable, единственная проблема возникает из-за вызова функции std::abs.Как я вижу, std::abs не является функцией constexpr.

Как решить эту проблему без записи внутренней версии std :: abs, которая является действительной constexpr?

1 Ответ

0 голосов
/ 26 октября 2018

Вы видели отчет об ошибках MS Developer https://developercommunity.visualstudio.com/content/problem/323938/broken-parsing-of-greater-than-comparison-operator.html

Эта ошибка, кажется, исправлена ​​в Предварительном просмотре 2019 года.Но до тех пор, как отмечается в сообщении об ошибке.

Далее следует свернуть приведенный выше код для воспроизведения ошибки в версии 2017 года.Исправление отмечено в последовательности посещения ...;if Выражение constexpr (...; if (...> ....) с помощьюround () или логики реверсирования оператора> Примечание: ">" после посещения, если последовательность constexpr может вызвать проблемы в других ситуациях.

#include <tuple>
#include <variant>
#include <optional>

inline std::tuple<float, float> _convertCentsToAlterAndCents(float shift)
{ 
    return std::tuple{shift, shift};
}
//using AccidentalVar = std::variant<std::nullopt_t, int, float, double, const char*, std::string, Accidental, Accidental::Ptr>;
using AccidentalVar = std::variant<std::nullopt_t, int, float, double, const char*>;

void microtone(float cents) {} 

//void Pitch::accidental(AccidentalVar value)
void test(AccidentalVar value)
{
    //std::visit([this](auto&& arg)
    std::visit([&](auto&& arg)
    {
        using T = std::remove_cv_t<std::remove_reference_t<decltype(arg)>>;

        if constexpr (std::is_same_v<T, int> ||
            std::is_same_v<T, float> ||
            std::is_same_v<T, double>)
        {
            auto[alter, cents] = _convertCentsToAlterAndCents(static_cast<float>(arg) * 100.f);
            //_accidental = std::make_shared<Accidental>(alter);

            //if (abs(cents) > 0.01f) // error in vs 2017
            if ( ( abs(cents) > 0.01f ) ) // FIX 1 or
            //if( 0.01f <= abs(cents) ) // or FIX 2
                microtone(cents);
        }
        // remaining code removed...
    },
    value);
}
...