Стиль шаблонов программирования - PullRequest
0 голосов
/ 11 апреля 2011

Если бы у вас была опция, какую бы вы выбрали?

template<class CheckEveryNode<true>>
struct X;

or 

template<bool CheckEveryNode>
struct X;

Это не очень очевидно с точки зрения дизайнеров, с одной стороны у нас есть читабельность в реальном коде:

//taking first approach
//somewhere in the code
X<CheckEveryNode<false>> x;

на второй стороне есть гораздо больше, чтобы напечататьа кто-то предпочел бы:

//taking second approach
//somewhere in the code
X<false> x;//but here we don't really see immediately what the false means.  

Итак, с нетерпением ждем ваших мнений / предложений

Ответы [ 5 ]

2 голосов
/ 11 апреля 2011

Часто увлекаясь метапрограммированием, я могу рекомендовать только "многословный" подход, но мне не очень нравится первый подход, который вы предлагаете.

В идеале, когда вы используете Политики, вы не просто передаете флаг, вы передаете объект Политики, который позволит пользователю настраивать его по своему желанию, а не полагаться на ваши собственные предопределенные значения.

Например:

struct NodeCheckerTag {};

struct CheckEveryNode {
  typedef NodeCheckerTag PolicyTag;
  void check(List const& list);
};

struct CheckFirstNode {
  typedef NodeCheckerTag PolicyTag;
  void check(List const& list);
};

template <typename Rand>
struct CheckSomeNodes {
  typedef NodeCheckerTag PolicyTag;
  CheckSomeNodes(Rand rand): _rand(rand) {}
  void check(List const& list);
  Rand _rand;
};

Таким образом, ваш класс должен позволять пользователю выбирать, какую политику выбрать:

template <typename NodeChecker>
class X: NodeChecker // allow stateful implementation but let EBO kick in
{
};

PolicyTag - наличие нескольких политик:

template <typename NodeChecker, typename NodeAllocator, typename NodeNotifier>
class X;

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

template <typename Tag, typename Default, typename... Policies>
struct PolicySelector
{
  typedef /**/ type;
};

template <typename... Policies>
class X: Policies...
{
  typedef typename PolicySelector<NodeCheckerTag, CheckNoNode,
    Policies...>::type NodeCheckerPolicy;
  typedef typename PolicySelector<NodeAllocatorTag, StdAllocator,
    Policies...>::type NodeAllocatorPolicy;
  ...
};

Обратите внимание, что при наследовании от политик выбор может быть ненужным, если вы заботитесь только о вызове некоторых функций. Это необходимо, только если вам нужны внутренние определения типов, скрытые в политиках, так как они должны быть явно определены в производном классе (здесь X).

1 голос
/ 11 апреля 2011

Если вас беспокоит то, что происходит, когда у вас несколько политик, и вы не знаете, что означают различные логические значения, вы можете исключить все логические значения и использовать теги.

struct CheckEvery { };
struct CheckNone { };

template<typename Check> struct Thingy;
template<> Thingy<CheckEvery> { ... };
template<> Thingy<CheckNone> { ... };

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

struct CheckEvery { bool shouldCheck(int) { return true; } };
struct CheckNone { bool shouldCheck(int) { return false; } };
struct CheckOdds { bool shouldCheck(int i) { return i % 2; } };

template<typename Checker> struct Thingy {
  Checker checker;
  void someFunction(int i) { if(checker.shouldCheck(i)) check(i); }
};

Пример не очень удачный, но он дает вам идею. Например, вы, вероятно, захотите предоставить объект Checker конструктору Thingy.

1 голос
/ 11 апреля 2011

Первый

template<class CheckEveryNode<true>>
struct X;

Было бы неправильно, это должно быть

template<template<bool> CheckEveryNode>
struct X{};

, что потребовало бы, чтобы вы специализировались либо на истинном, либо на ложном условии:

// above is true case, below is false case
template<>
struct X<CheckEveryNode<false> >{};

Или используйте частичную специализацию следующим образом:

template<class CheckEveryNode>
struct X;

template<bool B>
struct X<CheckEveryNode<B> >{
  // real implementation
};

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

0 голосов
/ 11 апреля 2011

Мне также нравится второй. Моя философия заключается в том, зачем создавать дополнительный тип, если вам не нужно?

0 голосов
/ 11 апреля 2011

Первый подход выглядит громоздким. Я бы пошел на второй в отсутствие убедительного обоснования для первого. Что касается читабельности, второй читабелен. Фактически, первое снижает читабельность из-за синтаксиса хотчпота.

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