Search code examples
c++c++11templatestype-traits

Round Brackets vs Curly Brackets on constructor calling


Following codes work as expected with results:

ASM generation compiler returned: 0
Execution build compiler returned: 0
Program returned: 0
same
same
same
#include <iostream>
#include <type_traits>

struct Test {
    Test() {
        std::cout << "Test ctor\n";
    }
    int func() {
        return 1;
    }
};

int main() {
    if (std::is_same_v<decltype(std::add_rvalue_reference<Test>::type{}.func()),int>) {
        std::cout <<"same\n";
    } else {
        std::cout <<"different\n";
    }
    if (std::is_same_v<decltype(Test().func()),int>) {
        std::cout <<"same\n";
    } else {
        std::cout <<"different\n";
    }
    if (std::is_same_v<decltype(std::type_identity<Test>::type().func()),int>) {
        std::cout <<"same\n";
    } else {
        std::cout <<"different\n";
    }
}

However, if I replace std::add_rvalue_reference<Test>::type{} with std::add_rvalue_reference<Test>::type(), the following compilation errors are generated:

<source>:14:33: error: reference to type 'Test' requires an initializer
    if (std::is_same_v<decltype(std::add_rvalue_reference<Test>::type().func()),int>) {
                                ^
1 error generated.
ASM generation compiler returned: 1
<source>:14:33: error: reference to type 'Test' requires an initializer
    if (std::is_same_v<decltype(std::add_rvalue_reference<Test>::type().func()),int>) {
                                ^
1 error generated.
Execution build compiler returned: 1

Does anyone know what is causing std::add_rvalue_reference<Test>::type() to fail to call the constructor of Test, while Test() and std::type_identity<Test>::type() are fine?


Solution

  • @RemyLebeau is right. It is not allowed to value-initialize a reference, while list-initializing a reference from {} works by creating a temporary.

    [dcl.init]:

    A program that calls for default-initialization or value-initialization of an entity of reference type is ill-formed.

    [dcl.init.list]:

    List-initialization of an object or reference of type T is defined as follows:

    • [...]
    • Otherwise, if T is a reference type, a prvalue temporary of the type referenced by T is list-initialized, and the reference is bound to that temporary.