Предотвратить множественные экземпляры шаблонного класса - PullRequest
0 голосов
/ 05 марта 2019

У меня есть шаблонный класс, скажем:

template <int X>
struct Foo {
  static int get() {return X;}
};

Я, конечно, могу явно создать экземпляр нужной версии:

template class Foo<1>;

Я хочу выдать ошибку во время компиляции, еслипопытка второго явного создания экземпляра.

template class Foo<1>;
template class Foo<2>; // How to error here at compile time?

Возможно ли это?

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

Если есть способ сделать это, работает ли он без явной реализации шаблона?


Context

Я пишу полностью статическую библиотеку классов для управления некоторым оборудованием на используемом мной микроконтроллере.Я хочу упростить изменение параметра времени компиляции (X) и поэтому использую шаблоны.#define не допускается.constexpr не будет работать, как бы вы #include зависимый исходный файл?

В частности, у меня есть функция init(), которую можно запустить только один раз, и я на самом деле использую __attribute__((constructor)) заставить его работать для меня до main().Если какой-то другой пользователь библиотеки непреднамеренно создаст экземпляр второго экземпляра, произойдут плохие вещи.

1 Ответ

0 голосов
/ 05 марта 2019

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

class Foo {
private:
    template<int X>
    struct BarImpl {
        static int get() { return X; }
    };

public:
    using Bar = BarImpl<1>;
};

Затем вы можете использовать его следующим образом:

int i = Foo::Bar::get();
//int j = Foo::BarImpl<2>::get(); // Error, BarImpl is private

Кроме того, поскольку вы знаете, что будет создан только один экземпляр шаблона, и знаете, какой из них, вы можете (но, конечно, не обязаны) разделить объявление и определение шаблона в.hpp и файл .cpp, например:

// Foo.hpp
class Foo {
private:
    template<int X>
    struct BarImpl {
        static int get();
    };

    static constexpr int Y = 1;
public:
    using Bar = BarImpl<Y>;
};

// Foo.cpp
template<>
int Foo::Bar::get() {
    return Y;
}

Поскольку X недоступен через Foo::Bar, мы должны где-то сохранить параметр (здесь, в Y).Если вы не можете использовать constexpr, вы можете просто сделать это const.Это также имеет преимущество в именовании вашего параметра вместо того, чтобы просто иметь «магическое значение».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...