std::convertible_to 无法识别显式可转换类型

WAR*_*ead 2 c++ c++-concepts c++20 compiler-explorer

根据convertible_to中的 en.cppreference.com :

概念convertible_to<From, To>指定与std::declval()相同类型和值类别的表达式可以隐式和显式转换为To类型,并且两种转换形式是等效的。

我理解这意味着如果有成员,该convertible_to概念将被识别convertible_to<U, V>为满意。即使运算符是显式的而不是隐式运算符。Uexplicit operator V()

但是我发现msvc中不是这样的。

由于静态断言,以下代码无法编译:

#include <concepts>
#include <iostream>

class ExplictClass
{
public:
    inline explicit operator int() const
    {
        return 5;
    }
};

int main()
{
    static_assert(std::convertible_to<ExplictClass, int>, "Explicit not convertible?"); // Fails here, concept not satisfied.
}
Run Code Online (Sandbox Code Playgroud)

这是我对概念的误解std::convertible_to,代码中的错误,还是 en.cppreference.com 中的错误,或者 msvc v19 的不一致性。

附上使用 x64 msvc v19.latest 的编译器资源管理器的链接,其中包含上述代码

编译器浏览器

编辑:

实际需要convertible_to是生成一个to_string函数模板,该模板可以与声明的可转换类型很好地配合,如下所示:

template<class T>
std::string to_string(T val)
{
    std::ostringstream stream;
    stream << val;
    return stream.str();
}

template<Convertible<std::string> T>
std::string to_string(T val)
{
    return static_cast<std::string>(val);
}
Run Code Online (Sandbox Code Playgroud)

在这里,我希望像const char*,char*那样的类型,像ExplicitClass(with explicit operator std::string) all 这样的类型使用第二种方法,第一种方法是后备选项

Jan*_*tke 6

std::convertible_to需要显式转换1)。这可以从定义中看出:

template <class From, class To>
concept convertible_to =
  std::is_convertible_v<From, To> &&                   // implicit conversion
  requires { static_cast<To>(std::declval<From>()); }; // explicit conversion
Run Code Online (Sandbox Code Playgroud)

1) 注意:隐式可转换性几乎总是意味着显式可转换性

ExplicitClass只有显式转换为int,这意味着您可以写入ExplicitClass(0),但不可能写入ExplicitClass e = 0;,这需要隐式转换。

ExplicitClass如果您想要一个测试是否可以显式转换为 的概念int,您有两个选择:

A - 仅使用显式部分std::convertible_to

template <class From, class To>
concept explicitly_convertible_to = requires {
    static_cast<To>(std::declval<From>());
};

// assertion passes
static_assert(explicitly_convertible_to<ExplictClass, int>);

// constraint satisfied for T = ExplicitClass
template <explicitly_convertible_to<int> T>
int foo(T t);
Run Code Online (Sandbox Code Playgroud)

乙:使用std::constructible_from

// assertion passes
static_assert(std::constructible_from<int, From>);

// constraint satisfied for T = ExplicitClass
template <typename T>
requires std::constructible_from<int, T>
int foo(T t);
Run Code Online (Sandbox Code Playgroud)

请注意,std::constructible_from<To, From>将测试是否:

这意味着它std::constructible_from并不等同于 a static_cast,但它会完全按照您想要的类类型(如ExplicitClass.