Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can I use private default constructor in decltype()?

Look at the code:

#include <iostream>
#include <utility>

class test
{
private:
    test() { }
public:
    test foo() { return *this; }

    static const char *name() { return "test"; }
};

int main()
{
    std::cout << decltype(test().foo())::name() << std::endl;               // 1
    std::cout << decltype(std::declval<test>().foo())::name() << std::endl; // 2
}

I expected // 1 line cannot be compiled because the default constructor of test is private.

However, it works well. I tested it on my g++ 4.8.3 with -Wall -Wextra -Werror -pedantic in disbelief, but it works well without any errors or warnings.

(In addition, it seems to work well in GCC 4.9.1 as well.)

From this page, I guess we can use private default constructor if the expression is unevaluated. So, I tested the following to check it.

#include <iostream>
#include <utility>

class test
{
private:
    test(int) { }
public:
    test foo() { return *this; }

    static const char *name() { return "test"; }
};

int main()
{
    std::cout << decltype(test().foo())::name() << std::endl;               // 1
    std::cout << decltype(std::declval<test>().foo())::name() << std::endl; // 2
}

(live example)

As expected, it wasn't compiled.

But.... why?? How can it be possible? Can we use private members in unevaluated expression? Or is there a special rule for default constructors? Could you explain me why?

like image 924
ikh Avatar asked Sep 04 '14 10:09

ikh


People also ask

Is private constructor possible in C++?

Typically, constructors have public accessibility so that code outside the class definition or inheritance hierarchy can create objects of the class. But you can also declare a constructor as protected or private . Constructors may be declared as inline , explicit , friend , or constexpr .

What will happen if we make constructor private in C++?

If some constructor is private, it means that no one but the class itself (and friends) should be able to create instances of it using that constructor. Therefore, you can provide static methods like getInstance() to create instances of the class or create the instances in some friend class/method.

Why do we need private constructors in C++?

Private constructors are used to prevent creating instances of a class when there are no instance fields or methods, such as the Math class, or when a method is called to obtain an instance of a class.

How do you call a default constructor in C++?

base a declares a variable a of type base and calls its default constructor (assuming it's not a builtin type). base a(); declares a function a that takes no parameters and returns type base .


1 Answers

It shouldn't compile. C++11 [class.temporary] has this to say about creating a temporary object:

12.2/1 Even when the creation of the temporary object is unevaluated or otherwise avoided, all the semantic restrictions shall be respected as if the temporary object had been created and later destroyed. [ Note: even if there is no call to the destructor or copy/move constructor, all the semantic restrictions, such as accessibility and whether the function is deleted, shall be satisfied. However, in the special case of a function call used as the operand of a decltype-specifier, no temporary is introduced, so the foregoing does not apply to the prvalue of any such function call. — end note ]

So, even when unevaluated, you're still restricted by the accessibility of any functions (including constructors) needed to create and destroy the temporary. The final sentence of the note clarifies that a function like declval can be used to avoid this obstacle.

like image 192
Mike Seymour Avatar answered Oct 05 '22 00:10

Mike Seymour