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?
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 .
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.
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.
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 .
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With