Visual C++:将数组转发为指针

Sim*_*rne 8 c++ compiler-errors language-lawyer c++11 visual-studio-2015

我已经删除了一些在Visual Studio 2015上无法编译的C++ 11代码到我认为应该编译的以下代码(并且使用clang和gcc):

#include <utility>

void test(const char* x);

int main()
{
    const char x[] = "Hello world!";

    test(std::forward<const char*>(x));    
}
Run Code Online (Sandbox Code Playgroud)

我理解forward这里没有必要打电话.这是从一个更复杂的代码中减少的,它将可变参数中的任何数组衰减到指针并转发所有内容.我确信可以通过模板专业化或SFINAE找到解决这个问题的方法,但是在我走这条路之前,我想知道它是否是有效的C++.编译器是Visual Studio 2015,可以在此在线MSVC编译器上重新创建问题.编译错误是:

main.cpp(13): error C2665: 'std::forward': none of the 2 overloads could convert all the argument types
c:\tools_root\cl\inc\type_traits(1238): note: could be '_Ty &&std::forward<const char*>(const char *&&) noexcept'
        with
        [
            _Ty=const char *
        ]
c:\tools_root\cl\inc\type_traits(1231): note: or       '_Ty &&std::forward<const char*>(const char *&) noexcept'
        with
        [
            _Ty=const char *
        ]
main.cpp(13): note: while trying to match the argument list '(const char [13])'
Run Code Online (Sandbox Code Playgroud)

更新:

@Yakk提出了一个更像这样的例子:

void test(const char*&& x);

int main()
{
    const char x[] = "Hello world!";

    test(x);    
}
Run Code Online (Sandbox Code Playgroud)

这提供了更多信息错误:

main.cpp(7): error C2664: 'void test(const char *&&)': cannot convert argument 1 from 'const char [13]' to 'const char *&&'
main.cpp(7): note: You cannot bind an lvalue to an rvalue reference
Run Code Online (Sandbox Code Playgroud)

再次,这编译在gcc和clang上.Visual C++的编译器标志是/EHsc /nologo /W4 /c.@Crazy Eddie建议这可能是VC++扩展,将临时文本作为非const引用传递.

Fal*_*ias 4

对我来说,这看起来像是 MSVC 中的一个错误,它试图巧妙地处理数组到指针,但却出错了。

分解你的第二个例子:

编译器需要const char*&&从 类型的左值初始化 a const char[13]。为此,8.5.3 表示它会创建一个类型的临时对象const char*并使用 对其进行初始化const char[13],然后将引用绑定到该临时对象。

const char*从 a初始化 aconst char[13]涉及一个简单的数组到指针的转换,产生一个纯右值,const char*然后将其复制到临时值中。

因此,无论 MSVC 怎么说,转换都是明确定义的。

在您的第一个示例中,不是 test() 导致了问题,而是对std::forward. std::forward<const char*>有两个重载,MSVC 抱怨这两个都不可行。这两种形式是

const char*&& std::forward(const char*&&);
const char*&& std::forward(const char*&);
Run Code Online (Sandbox Code Playgroud)

一种采用左值引用,另一种采用右值引用。当考虑任一重载是否可行时,编译器需要找到从const char[13]到 的引用的转换序列const char*

由于左值引用不是 const(它是对指向 const char 的指针的引用;指针本身不是 const),因此编译器无法应用上面概述的转换序列。事实上,没有任何转换序列是有效的,因为数组到指针的转换需要临时值,但不能将非常量左值引用绑定到临时值。因此,MSVC 拒绝左值形式是正确的。

然而,正如我在上面所建立的,右值形式应该被接受,但被 MSVC 错误地拒绝。