Почему я могу использовать закрытый конструктор по умолчанию в decltype()?


Посмотрите на код:

#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
}

Я ожидал, что строка // 1 не может быть скомпилирована, потому что конструктор по умолчанию test является частным.

Тем не менее, это работает хорошо. я протестировал его на моем g++ 4.8.3 с -Wall -Wextra -Werror -pedantic в неверии, но он работает хорошо без каких-либо ошибок или предупреждений.

(кроме того, он, по-видимому, хорошо работает и в GCC 4.9.1.)

Из этой страницы , я думаю, мы можем использовать частный конструктор по умолчанию, если выражение не оценено. Итак, я проверил следуя, чтобы проверить это.

#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
}

(живой пример)

Как и ожидалось, он не был скомпилирован.

Но.... почему?? Как это может быть возможно? Можем ли мы использовать частные члены в ненулевом выражении? Или существует специальное правило для конструкторов по умолчанию? Не могли бы вы объяснить мне, почему?

1 7

1 ответ:

Он не должен компилироваться. C++11 [класс.temporary] имеет это сказать о создании временного объекта:

12.2 / 1 Даже если создание временного объекта не оценено все семантические ограничения должны соблюдаться, как если бы временный объект был создан, а затем уничтожен. [Примечание: даже если нет вызова деструктора или конструктора копирования / перемещения, все семантические ограничения , такие как доступность и будет ли функция удалена, должно быть удовлетворено. Однако в частном случае вызова функции, используемой в качестве операндаописателя decltype , не вводится временное значение, поэтому вышеизложенное не относится к prvalue любого такого вызова функции. - Конечная нота]

Таким образом, даже когда вы не оцениваете, вы все еще ограничены доступностью любых функций (включая конструкторы), необходимых для создания и уничтожения временного. Финал предложение Примечания уточняет, что функция, подобная declval, может быть использована, чтобы избежать этого препятствия.