2014-02-17 3 views
1

Как я могу гарантировать, что будет вызван конкретный метод во время компиляции?Обеспечение метода вызова во время компиляции

Например, предположим, что у меня есть объект с 2-мя методами:

struct Foo 
{ 
    ... func1(...); 
    ... func2(...); 
}; 

и я хочу, чтобы убедиться, что func1 вызывается перед вызовом func2, то есть:

int main() 
{ 
    Foo f; 
    ... 
    f.func1(...); 
    f.func2(...); 
    f.func2(...); // and so on 
} 

, но я хочу для генерации ошибки компиляции, если я сделаю что-то подобное:

int main() 
{ 
    Foo f; 
    ... 
    f.func2(...); // generate a compile error due the fact that func1 must be called first 
    f.func1(...); 
    f.func2(...); // and so on 
} 
+0

Вы можете попробовать использовать 'constexpr', но в этом случае он не будет работать. (В любом случае не гарантируется работа). –

+0

Я думаю, это можно сделать только с помощью анализаторов кода. Сам компилятор может только предупредить вас о неиспользуемой функции - AFAIK. –

+2

Если вам нужно сделать это, вероятно, вы должны продолжать думать о лучшем дизайне класса.Это скрупулезный антипаттерн: http://en.wikipedia.org/wiki/Sequential_coupling –

ответ

5

Нет реального способа обеспечить соблюдение t его во время компиляции. Это то, что сам объект должен будет обеспечивать с помощью контроля времени выполнения

11

Хотя любопытно, почему вы это делаете, общее замечание, что вы должны подвергать пользователя интерфейс, который не может быть использован неправильно. Кишки идут частные:

struct Foo 
{ 
public: 
    void callme() 
    { 
     func1(); 
     func2(); 
    } 

private: 
    ... func1(...); 
    ... func2(...); 


}; 

int main() 
{ 
    Foo f; 
    f.callme(); 
} 

Если необходимо применять один инициализацию времени объектов, сделать это в конструкторе: интерфейсы

struct Foo 
{ 
public: 
    Foo() 
    { 
     func1(); 
    } 

    func2(...); 
private: 
    ... func1(...); 
}; 

int main() 
{ 
    Foo f; // func1() called automagically 
    f.func2(); 
} 

Проектирование класса, вы должны ВСЕГДА думать о худших вещах: пользователи никогда не читают документация, пользователи всегда забывают позвонить foo.initialize(), пользователи всегда забывают освободить память и утечки и т. д.

+0

Я бы также упомянул, что вы можете передавать аргументы из 'callme' в' func1 ... funcn', используя 'std :: forward '. С достаточным определением вы можете создать подпись 'callme' автоматически из списка функций, которые она должна использовать, делая ее более прозрачной. –

+0

Вы спросили меня, почему я хочу этого. Взгляните на эту статью (http://www.di.unipi.it/~nids/docs/templates_vs_inheritance.html). Здесь, когда вы делаете шаблон стратегии (не уверен, что это действительно шаблон стратегии), используя шаблоны, вы инициализируете объект, а не конструктор, но вызываете функцию init. Я хочу убедиться, что пользователь сделал это, но во время компиляции. – Amadeus

+0

@ TomásBadan Я не вижу необходимости в методах 'init()' в этом примере. Фактически, они * могут быть заменены на конструкторы. Таким образом, независимо от того, где и кто ранее вызывал 'init()', теперь просто передаются аргументы конструктору или фабрике (которая передает их конструктору). – Drop

3

Один из способов, который приходит на ум, состоит в том, чтобы вернуть func1() объект, который действует как прокси для func2() :

class Foo { 
public: 
    Proxy func1(); 
private: 
    void func2(); 
    friend class Proxy; 
}; 

class Proxy { 
private: 
    explicit Proxy(Foo& f) : f_(f) {} 
public: 
    void func2() { 
     f_.func2(); 
    } 
    friend class Foo; 
}; 

Foo f; 
f.func1().func2(); 

Другим способом (и мой любимый), чтобы позволить func1() быть конструктор или использовать другой класс, который вызывает func1() в это конструктор:

class Foo 
{ 
private: 
    void func1(), func2(); 
    friend class FooUser; 
}; 

class FooUser 
{ 
public: 
    explicit Proxy(FooUser& f) : f_(f) { 
     f.func1(); 
    } 

    void func2() { 
     f_.func2(); 
    } 
}; 
1

Компилятор может t обеспечить соблюдение порядка вызовов функций, поскольку в целом это можно определить только во время выполнения. Но он может обеспечить инициализацию объекта до того, как объект будет использоваться. Таким образом, лучший способ получить проверку времени компиляции - сделать то, что делает func1 в конструкторе - либо часть конструктора Foo, либо вспомогательный объект, который необходимо создать для вызова func2.

1

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

#define FLAG 
func1(); 

и func2() в

#ifdef FLAG 
func2(); 
#else 
#error func1 should be called first! 
#endif 

Таким образом, вы получите ошибку компиляции, если func2() будет упомянуто выше в тексте, то func1. Это не значит, что он будет действительно вызван раньше во время исполнения.

Смежные вопросы