-->

Is this an incorrect warning?

2020-07-18 05:44发布

问题:

Let's see this code pattern I'm seeing often:

struct Foo
{
    template <typename T>
    T* as1() { /* ... */ }

    template <typename T>
    T* as2(T*) { /* ... */ }  
};   

The former method is to be used like this:

    SomeComplexTypeAndNotAuto * a = foo.as1<SomeComplexTypeAndNotAuto>();

While the latter is more convenient to use since you don't need to repeat the complex type:

    SomeComplexTypeAndNotAuto * a = foo.as2(a); 

However, most compiler rejects the 2nd case with a Wuninitialized warning:

warning: variable 'a' is uninitialized when used within its own initialization [-Wuninitialized]

It's quite clear the variable is not used in the initialization, only its type is. Is there a way to avoid this warning without dealing with the hell of per-compiler pragma ?

Edit:

It's not clear from my initial post, but when I wrote SomeComplexTypeNotAuto, I meant that such code like this: auto a = foo.as2(a); can not be resolved since you have to provide one type to allow the compiler to deduce it.

My question was specific to the fact that method as2() is a template, as as such must be visible at specialization time for a type T. So the compiler can see that the argument T* does not even have a name so it's not used/usable from within the function. As such, I don't get why it warns about the "unused variable" warning since it's clear it's not used.

回答1:

It's quite clear the variable is not used in the initialization

On the contrary, it is quite clear that the variable is used in the initialisation of the function argument. The behaviour of the program is undefined.

Is this an incorrect warning?

No, the warning is correct.


A simple fix is to change the argument into a reference:

T* as2(T*&)

Just be extra sure to not actually read the referred value.

Since C+11, you can use auto instead however.



回答2:

The warning is correct.

a has an unspecified value in its own initialiser, and passing it as a function argument by value requires it to be copied, which requires reading from it, which has undefined behaviour.

It does not matter that you do not then use what would have been the resulting value.


You can "fix" it by preventing the copy (with a by-reference argument) but you're going to end up with very strange and unusual code that confuses your readers. I really do not advise this approach.

Just spell out the type, ideally making it shorter and more readable first.

Conventionally, we skip the repeated type name like this:

auto* a = foo.as1<SomeComplexTypeAndNotAuto>();

(e.g. when using std::make_shared and friends)

Also, look up the visitor pattern.



回答3:

It's not clear that the variable is not used int the initialization. Anything could be happening inside as2.

If the variable is not being used, then don't pass it - use explicit template instantiation instead.