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

时间:2022-09-01 11:27:51

I've cut down some C++ 11 code that was failing to compile on Visual Studio 2015 to the following which I think should compile (and does with clang and gcc):

我已经将一些在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));    
}

I understand the call to forward isn't necessary here. This is cut down from a much more complex bit of code that decays any arrays in a variadic argument down to pointers and forwards everything on. I'm sure can find ways to work around this with template specialization or SFINAE, but I'd like to know whether it's valid C++ before I go down that road. The compiler is Visual Studio 2015, and the problem can be recreated on this online MSVC compiler. The compile error is:

我知道在这里没有必要呼吁前进。这是从一段复杂得多的代码中删除的,这段代码将变量参数中的任何数组衰减为指针,并将所有内容转发出去。我肯定可以找到解决这个问题的方法,比如模板专门化或SFINAE,但是我想在我继续之前知道它是否有效。编译器是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])'

Update:

更新:

@Yakk has suggested an example more like this:

@Yakk举了一个类似的例子:

void test(const char*&& x);

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

    test(x);    
}

Which gives a more informative error:

这就产生了一个更有用的错误:

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

Again, this compiles on gcc and clang. The compiler flags for Visual C++ were /EHsc /nologo /W4 /c. @Crazy Eddie suggests this might be down to a VC++ extension to pass temporaries as non const references.

同样,这是在gcc和clang上编译的。Visual c++的编译器标志是/EHsc /nologo /W4 / C。@Crazy Eddie认为这可能是一个vc++的扩展,可以将临时文件作为非const引用传递。

3 个解决方案

#1


4  

To me this looks like a bug in MSVC where it tries to be clever with array-to-pointer and gets it wrong.

在我看来,这就像是MSVC中的一个bug,它试图巧妙地使用arrayto -pointer,结果却出错了。

Breaking down your second example:

分解第二个例子:

The compiler needs to initialize a const char*&& from an lvalue of type const char[13]. To do this, 8.5.3 says it creates a temporary of type const char* and initializes it with the const char[13], then binds the reference to the temporary.

编译器需要从const char[13]类型的lvalue初始化const char*&& &。为此,8.5.3说它创建一个临时的const char*类型,并使用const char[13]初始化它,然后将引用绑定到临时的。

Initializing a const char* from a const char[13] involves a simple array-to-pointer conversion, yielding a prvalue of const char* which is then copied into the temporary.

从const char[13]初始化const char*涉及到一个简单的arrayto -pointer转换,生成const char*的prvalue,然后将其复制到临时字符中。

Thus the conversion is well defined, despite what MSVC says.

因此,不管MSVC怎么说,转换是很明确的。

In your first example, it's not test() that is causing the issue, but the call to std::forward. std::forward<const char*> has two overloads, and MSVC is complaining neither is viable. The two forms are

在您的第一个示例中,它不是导致问题的测试(),而是调用std::forward。std::forward 有两个过载,MSVC抱怨两者都不可行。两种形式是

const char*&& std::forward(const char*&&);
const char*&& std::forward(const char*&);

One takes an lvalue reference, one takes an rvalue reference. When considering whether either overload is viable, the compiler needs to find a conversion sequence from const char[13] to a reference to const char*.

一个是lvalue引用,一个是rvalue引用。在考虑这两个重载是否可行时,编译器需要找到一个从const char[13]到const char*的引用的转换序列。

Since the lvalue reference isn't const (it's a reference to a pointer to a const char; the pointer itself isn't const), the compiler can't apply the conversion sequence outlined above. In fact, no conversion sequence is valid, as the array-to-pointer conversion requires a temporary but you can't bind non-const lvalue references to temporaries. Thus MSVC is correct in rejecting the lvalue form.

因为lvalue引用不是const(它是指向const字符的指针的引用;指针本身不是const),编译器不能应用上面列出的转换序列。实际上,没有一个转换序列是有效的,因为arrayto -指针转换需要临时的,但是您不能将非const lvalue引用绑定到临时文件。因此MSVC拒绝lvalue形式是正确的。

The rvalue form, however, as I've established above, should be accepted but is incorrectly rejected by MSVC.

然而,正如我在上面所提到的,rvalue格式应该被接受,但被MSVC错误地拒绝了。

#2


0  

I believe std::decay<const char []>::type is what you're looking for http://en.cppreference.com/w/cpp/types/decay

我相信std::衰变 :::type就是您要查找的http://en.cppreference.com/w/cpp/types/衰变

#3


-1  

I think it should compile, but why are you bothering to use std::forward?

我认为它应该被编译,但是你为什么要用std::forward?

Isn't the correct solution simply to replace

仅仅替换不是正确的解决方案

std::forward<const char*>(x)

with:

:

(const char*)x

or for the generic case, replace:

或在一般情况下,替换:

std::forward<decay_t<decltype(x)>>(x)

with:

:

decay_t<decltype(x)>(x)

Using std::forward doesn't seem to have any purpose here, you have an array, you want to decay it to a pointer, so do that.

使用std::forward似乎没有任何目的,你有一个数组,你想把它分解成一个指针,就这么做。

#1


4  

To me this looks like a bug in MSVC where it tries to be clever with array-to-pointer and gets it wrong.

在我看来,这就像是MSVC中的一个bug,它试图巧妙地使用arrayto -pointer,结果却出错了。

Breaking down your second example:

分解第二个例子:

The compiler needs to initialize a const char*&& from an lvalue of type const char[13]. To do this, 8.5.3 says it creates a temporary of type const char* and initializes it with the const char[13], then binds the reference to the temporary.

编译器需要从const char[13]类型的lvalue初始化const char*&& &。为此,8.5.3说它创建一个临时的const char*类型,并使用const char[13]初始化它,然后将引用绑定到临时的。

Initializing a const char* from a const char[13] involves a simple array-to-pointer conversion, yielding a prvalue of const char* which is then copied into the temporary.

从const char[13]初始化const char*涉及到一个简单的arrayto -pointer转换,生成const char*的prvalue,然后将其复制到临时字符中。

Thus the conversion is well defined, despite what MSVC says.

因此,不管MSVC怎么说,转换是很明确的。

In your first example, it's not test() that is causing the issue, but the call to std::forward. std::forward<const char*> has two overloads, and MSVC is complaining neither is viable. The two forms are

在您的第一个示例中,它不是导致问题的测试(),而是调用std::forward。std::forward 有两个过载,MSVC抱怨两者都不可行。两种形式是

const char*&& std::forward(const char*&&);
const char*&& std::forward(const char*&);

One takes an lvalue reference, one takes an rvalue reference. When considering whether either overload is viable, the compiler needs to find a conversion sequence from const char[13] to a reference to const char*.

一个是lvalue引用,一个是rvalue引用。在考虑这两个重载是否可行时,编译器需要找到一个从const char[13]到const char*的引用的转换序列。

Since the lvalue reference isn't const (it's a reference to a pointer to a const char; the pointer itself isn't const), the compiler can't apply the conversion sequence outlined above. In fact, no conversion sequence is valid, as the array-to-pointer conversion requires a temporary but you can't bind non-const lvalue references to temporaries. Thus MSVC is correct in rejecting the lvalue form.

因为lvalue引用不是const(它是指向const字符的指针的引用;指针本身不是const),编译器不能应用上面列出的转换序列。实际上,没有一个转换序列是有效的,因为arrayto -指针转换需要临时的,但是您不能将非const lvalue引用绑定到临时文件。因此MSVC拒绝lvalue形式是正确的。

The rvalue form, however, as I've established above, should be accepted but is incorrectly rejected by MSVC.

然而,正如我在上面所提到的,rvalue格式应该被接受,但被MSVC错误地拒绝了。

#2


0  

I believe std::decay<const char []>::type is what you're looking for http://en.cppreference.com/w/cpp/types/decay

我相信std::衰变 :::type就是您要查找的http://en.cppreference.com/w/cpp/types/衰变

#3


-1  

I think it should compile, but why are you bothering to use std::forward?

我认为它应该被编译,但是你为什么要用std::forward?

Isn't the correct solution simply to replace

仅仅替换不是正确的解决方案

std::forward<const char*>(x)

with:

:

(const char*)x

or for the generic case, replace:

或在一般情况下,替换:

std::forward<decay_t<decltype(x)>>(x)

with:

:

decay_t<decltype(x)>(x)

Using std::forward doesn't seem to have any purpose here, you have an array, you want to decay it to a pointer, so do that.

使用std::forward似乎没有任何目的,你有一个数组,你想把它分解成一个指针,就这么做。