Много стандартов кодирования и более длинные документы и даже книги (Руководство по проектированию Платформы) были записаны по этой теме, но большая часть этого только помогает на довольно низком уровне.
существует также вопрос вкуса. API могут соблюсти каждое правило в любом своде правил, и все еще высосать, из-за рабского соблюдения различных идеологий в моде. Недавний преступник является ориентацией шаблона, где Шаблоны "одиночка" (немного больше, чем инициализированные глобальные переменные) и Шаблоны "фабрика" (способ параметризовать конструкцию, но часто реализовываемый если не необходимый) злоупотребляются. В последнее время более вероятно, что Инверсия управления (IoC) и связала взрыв в количестве крошечных интерфейсных типов, которое добавляет избыточную концептуальную сложность к проектам.
лучшие обучающие программы для вкуса являются имитацией (читающий много кода и API, узнавая, какие работы и не работает), опыт (делающий ошибки и извлекающий уроки из него) и думающий (не просто сделайте то, что является модным ради самого себя, думайте перед действием).
Чтобы получить ошибку времени компиляции, реализуйте ее как:
template<typename T>
T GetGlobal(const char *name) { T::unimplemented_function; }
// `unimplemented_function` identifier should be undefined
Если вы используете Boost, вы можете сделать его более элегантным:
template<typename T>
T GetGlobal(const char *name) { BOOST_STATIC_ASSERT(sizeof(T) == 0); }
Стандарт C ++ гарантирует, что не существует такого типа, который имеет sizeof равно 0, поэтому вы получите ошибку времени компиляции.
Как sbi предложил в своих комментариях, последнее может быть сокращено до:
template<typename T>
T GetGlobal(const char *name) { char X[!sizeof(T)]; }
Я предпочитаю первое решение, потому что оно дает больше четкое сообщение об ошибке (по крайней мере, в Visual C ++), чем другие.
Я бы посоветовал фактически не предоставлять реализацию, а просто декларировать метод.
Другой вариант - использовать утверждение во время компиляции. У Boost есть несколько таких чудовищ.
namespace mpl = boost::mpl;
BOOST_MPL_ASSERT((mpl::or_< boost::same_type<T, double>,
boost::same_type<T, int> >));
Есть также его версия сообщения, которая может помочь.
Если вы этого не сделаете Чтобы реализовать это, вы, по крайней мере, получите ошибку компоновщика. Если вам нужна ошибка времени компиляции, вы можете сделать это с помощью шаблонов классов:
template<typename T>
struct GlobalGetter;
template<>
struct GlobalGetter<int> {
static int GetGlobal(const char *name);
};
template<>
struct GlobalGetter<double> {
static double GetGlobal(const char *name);
};
template<typename T>
T GetGlobal(const char *name)
{
return GlobalGetter<T>::GetGlobal(name);
}
Ниже приведены методы, альтернативные использованию boost:
Объявление typedef для зависимого имени
Это работает, потому что поиск имени для DONT происходит только после замены 'T'. Это аналогичная (но легальная) версия примера, приведенного Кириллом
template <typename T>
T GetGlobal (const char * name) {
typedef typename T::DONT CALL_THIS_FUNCTION;
}
Использование неполного возвращаемого типа
Этот метод не работает для специализаций, но он будет работать для перегрузок. Идея состоит в том, что законно объявить функцию, которая возвращает неполный тип, но не вызывать ее:
template <typename T>
class DONT_CALL_THIS_FUNCTION GetGlobal (const char * name);