VS选择的专业错误吗?为什么?

时间:2018-12-06 13:40:12

标签: c++ visual-studio visual-studio-2017 c++17

以下是一些代码:

#include <iostream>
#include <functional>
#include <string>
#include <variant>

namespace detail
{
    std::string Foo(const double val)
    {
        return std::to_string(val);
    }
}

using Value = std::variant<std::monostate, double, int, bool, std::string>;
struct ReadStore {};

struct ValueException : std::runtime_error {};

using PrintConvType = std::function<Value(const Value&, ReadStore&)>;


template <typename InType, typename OutType, typename CallableType, CallableType Callable, bool Strict>
Value ConvWrapperImpl(const Value& value)
{
    if constexpr (std::is_same_v<InType, Value>)
    {
        return Callable(value);
    }
    else
    {
        if (value.index() != 0)
        {
            const auto* ptr = std::get_if<InType>(&value);
            if (ptr)
                return Callable(*ptr);
        }

        return value;
    }
}


template <typename T1, typename T2, T2 (*Callable)(const T1&), bool Strict = false>
Value ConvWrapper(const Value& value, ReadStore&)
{
    return ConvWrapperImpl<T1, T2, decltype(Callable), Callable, Strict>(value);
}

template <typename T1, typename T2, T2 (*Callable)(T1), bool Strict = false>
Value ConvWrapper(const Value& value, ReadStore&)
{
    return ConvWrapperImpl<T1, T2, decltype(Callable), Callable, Strict>(value);
}

int main()
{
    using namespace detail;

    ReadStore store;
    PrintConvType func = ConvWrapper<double, std::string, Foo>;

    Value result = func(3.14159, store);
     std::cout << std::get<std::string>(result) << '\n';
}

这是人为设计的MCVE,但是原始项目中的总体思路是为将Value的转换包装为某些回调函数的适当参数类型提供简捷方式,并包装所述函数的返回值的转换再次输入到Value

under GCC和Clang很好,但是我的Visual Studio 2017(v15.7.2)出现错误:

error C2440: 'specialization': cannot convert from 'std::string (__cdecl *)(const double)' to 'std::string (__cdecl *)(const double &)'
note: This conversion requires a reinterpret_cast, a C-style cast or a function-style cast
error C2973: 'convWrapper': invalid template argument 'std::string (__cdecl *)(const double)'
note: see declaration of 'ConvWrapper'

根据最后一个音符的链接位置,似乎选择了错误的ConvWrapper,然后在Callable签名不匹配时表现出惊讶。

奇怪的是on Godbolt with the same compiler selected, the code is accepted

是否有可能影响此配置?是我吗?

我该如何解决?更改配置还是更改代码?

2 个答案:

答案 0 :(得分:5)

引起问题的编译器标志是/permissive-一致性标志。从编译器命令中删除它,或在“调试”->“项目名称”属性-> C / C ++->“语言”->“一致性模式”中将其更改为“否”,即可对其进行编译。

答案 1 :(得分:2)

在c ++ 17中,您可以通过将*length替换为typename CallableType, CallableType Callable来避免重载。 那么MSVC不需要在类型之间进行转换。

auto Callable

具有类似用法(template <typename InType, auto Callable, bool Strict> Value ConvWrapperImpl(const Value& value) { if constexpr (std::is_same_v<InType, Value>) { return Callable(value); } else { if (value.index() != 0) { const auto* ptr = std::get_if<InType>(&value); if (ptr) return Callable(*ptr); } return value; } } template <typename T1, auto Callable, bool Strict = false> Value ConvWrapper(const Value& value, ReadStore&) { return ConvWrapperImpl<T1, Callable, Strict>(value); } 而非ConvWrapper<double, &Foo>):

ConvWrapper<double, std::string, &Foo>

Demo