VS2017 [15.8.6]如果constexpr在C2760消息中生成错误

时间:2018-10-08 11:39:14

标签: c++ compiler-errors visual-studio-2017 c++17 variant

自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)

如果我删除了{{1}中的constexpr,则会遇到一个if constexpr问题,因为static_cast<float>可以是arg (std::variant)(在访问者中进行了进一步处理)。

为什么简单条件std::nullopt无法建立?

非常感谢您的回答。

编辑:

也许我的问题与此有关:

constexpr

当条件评估操作的左侧操作数在constexpr上下文中无效时,Visual Studio 2017会正确引发错误。以下代码在Visual Studio 2015中编译,但在Visual Studio 2017中不能编译(C3615 constexpr函数'f'无法产生常量表达式):

abs(cents) > 0.01f

要更正此错误,请将array :: size()函数声明为constexpr或从f中删除constexpr限定符。

来源: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: 如果我在行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 } 上注释(在没有阈值条件的情况下调用if (abs(cents) > 0.01f)),则代码可以正常运行。因此,虽然microtone(cents)0.01f,而float constantcents,但是唯一的问题来自对float temporary variable函数的调用。如我所见,std::abs不是constexpr函数。

如何解决这一点而无需编写内部版本的constexpr有效的std :: abs?

1 个答案:

答案 0 :(得分:0)

您是否看到过MS Developer错误报告https://developercommunity.visualstudio.com/content/problem/323938/broken-parsing-of-greater-than-comparison-operator.html

上面的错误似乎已在2019 Preview中修复。 但是在此之前,如错误报告中所述。

下面将最小化上述代码以重现vs 2017中的错误。 该修复程序按访问顺序标记。 if constexpr(...; if(...> ....)表达式由()括起来或>运算符的逆逻辑 注意:访问后的“>”;如果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);
}