Есть ли способ сделать функцию-член НЕ вызываемой из конструктора?

У меня есть функция-член (метод), который использует

std::enable_shared_from_this::weak_from_this() 

Короче говоря: weak_from_this возвращает weak_ptr к этому. Одно предостережение: его нельзя использовать из конструктора. Если бы кто-то использовал мою функцию из конструктора унаследованного класса, weak_from_this в ее случае weak_ptr бы время истечения weak_ptr действия. Я защищаю это с проверкой утверждения, что это не истекло, но это проверка во время выполнения.

Есть ли способ проверить это во время компиляции?

Ответ 1

Я боюсь, что ответ "нет, это невозможно защитить от этого во время компиляции". Всегда трудно доказать отрицание, но учтите это: если бы можно было защитить функцию таким способом, это, вероятно, было бы сделано для weak_from_this и shared_from_this самой стандартной библиотеке.

Ответ 2

Нет, нет пути. Рассматривать:

void call_me(struct widget*);

struct widget : std::enable_shared_from_this<widget> {
    widget() {
        call_me(this);
    }

    void display() {
        shared_from_this();
    }
};

// later:

void call_me(widget* w) {
    w->display(); // crash
}

Дело в том, что есть причина, по которой вы хотите проверить, чтобы не вызывать shared_from_this в конструкторе. Подумай об этой причине. Это не shared_from_this что shared_from_this не может быть вызвано, а потому, что его возвращаемое значение еще не назначено. Это также не потому, что он никогда не будет назначен. Это потому, что он будет назначен позже при выполнении кода. Порядок работы является свойством среды выполнения вашей программы. Вы не можете утверждать во время компиляции порядок операций, который выполняется во время выполнения.

Ответ 3

Не как таковой, но - если производительность не является проблемой, вы можете добавить флаг, который указывает, что строительство завершено, и использовать его для сбоя во время выполнения с такими вызовами:

class A {

    // ... whatever ...
public:
    A() { 
        // do construction work
        constructed = true;
    }

    foo() {
        if (not constructed)  { 
            throw std::logic_error("Cannot call foo() during construction"); 
        }
        // the rest of foo
    }

protected:
    bool constructed { false };
}

Вы также можете сделать эти проверки применимыми только при компиляции в режиме DEBUG (например, при условной компиляции с использованием препроцессора - #ifndef NDEBUG), чтобы во время выполнения вы не получали #ifndef NDEBUG производительности. Имейте в виду, не noexcept хотя.

Альтернативой метанию может быть assert() 'ing.

Ответ 4

Обходной путь состоит в том, чтобы поместить объект в иерархию

struct Foo : Bar
{
    using Bar::Bar;
};

и написать функцию-член в Bar. Тогда конструктор Foo не сможет его увидеть и выдаст ошибку во время компиляции.

С делегированными конструкторами, доступными из С++ 11, это не так навязчиво, как могло бы быть когда-то.