Reputation: 10427
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
}
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?
Upvotes: 9
Views: 1501
Reputation: 254681
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.
Upvotes: 13