Вложенный шаблон специализации - PullRequest
23 голосов
/ 20 февраля 2009

Имея мозг пердеть ... Можно ли заставить что-то подобное работать?

template<int a> struct Foo
{
    template<int b> struct Bar;
};

template<int a> struct Foo<a>::Bar<1> //Trying to specialize Bar
{
};

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

Предложения приветствуются!

P.S .: Я забыл упомянуть, что специализация на Bar в рамках Foo явно не поддерживается языком. AFAICS, в любом случае.

Ответы [ 7 ]

12 голосов
/ 21 февраля 2009

Да, вы можете. Но вам нужно изменить структуру вызова, но чуть-чуть.

В частности, используйте шаблон стратегии для реструктуризации реализации функции-члена как класса (который разрешен быть специализированным).

Это разрешено, если класс стратегии не является вложенным (и, следовательно, не зависит от неспециализированного типа шаблона).

например. (это, вероятно, не является синтаксически правильным, но идея должна быть ясной)

template <class T>
class OuterThingThatIsNotSpecialized
{
  template <class U>
  void memberWeWantToSpecialize(const U& someObj_)
  {
    SpecializedStrategy<U>::doStuff(someObj_);
  }
};

template <class U>
struct SpecializedStrategy;

template <>
SpecializedStrategy<int>
{
  void doStuff(const int&)
  {
    // int impl
  } 
};

template <>
SpecializedStrategy<SomeOtherType>
{
  void doStuff(const SomeOtherType&)
  {
    // SOT impl
  } 
};

Это невероятно полезно, потому что вызовы OuterThingThatIsNotSpecialized для типов, где не существует реализации, просто не смогут скомпилироваться.

PS. Вы даже можете использовать эту стратегию для частичной специализации шаблонных функций, что в противном случае невозможно в C ++.

11 голосов
/ 30 июля 2010

В п. 18, раздел 14.7.3 стандарта 1998 года (ISO14882: 1998) говорится, что явная специализация (внутренних) классов-членов шаблона не допускается, когда (внешний) класс-шаблон явно не специализирован.

3 голосов
/ 20 февраля 2009

По этим постам:

http://www.cpptalk.net/template-member-function-specialization-vt11666.html

вы не можете специализировать элементы шаблона класса шаблона, не специализируя внешний класс. Они не цитируют стихи и главы. Моя копия "языка программирования C ++" не раскрывает ничего сразу, и моя копия стандарта находится дома (моей резервной копии, более известной здесь как "Крис", тоже нет рядом: -)

1 голос
/ 07 сентября 2014

Вот то, что я делал, и я думаю, что это проще / более точно соответствует тому, что вы пытаетесь сделать:

с помощником

template<int a> struct Foo
{
    template<int, int> struct Bar__;
    template<int b> using Bar = Bar__<b, b>;
};

template<int a> template<int b, int c> struct Foo<a>::Bar__
{
    // general case
    const static int x = 0;
};
template<int a> template<int b> struct Foo<a>::Bar__<b, 1>
{
    const static int x = 1;
};

int main(int argc, const char * argv[]) 
{   
    std::cout << Foo<1>::Bar<0>::x << "\r\n"; // general case - output 0
    std::cout << Foo<1>::Bar<1>::x << "\r\n"; // specialized case - output 1
    return 0;
}

ИЛИ - Помощник может быть удален, если вы не против удвоить специализацию каждый раз:

без помощника

template<int a> struct Foo
{
    template<int b, int c> struct Bar;
};

template<int a> template<int b, int c> struct Foo<a>::Bar
{
    // general case
    const static int x = 0;
};
template<int a> template<int b> struct Foo<a>::Bar<b, 1>
{
    const static int x = 1;
};

int main(int argc, const char * argv[])
{   
    std::cout << Foo<1>::Bar<0, 0>::x << "\r\n"; // general case - output 0
    std::cout << Foo<1>::Bar<1, 1>::x << "\r\n"; // specialized case - output 1
    return 0;
}
0 голосов
/ 06 июня 2014

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

namespace internal {
  template <int a, int b> struct FooBarHelper
  { /* ... */ };
  // Specialization
  template <int a> struct FooBarHelper<a, 1>
  { /* specialized version goes here */ };
}

template<int a> struct Foo
{
  template<int b> struct Bar : public internal::FooBarHelper<a, b>;
};

Конечно, это не так скрыто, как хотелось бы.

0 голосов
/ 18 ноября 2011

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

struct FooBase
{
    template<int b> struct Bar;
}
template<int a> struct Foo : public FooBase
{
};

struct FooBase::Bar<1> // specializing Bar
{
};
0 голосов
/ 20 февраля 2009

Вы не можете этого сделать. Я перепробовал много вариантов. Этот , однако, компилируется в GCC 4.1:

template<int a> struct Foo
{
    template<int b> struct Bar;
    template<1> struct Bar;
};

Редактировать (после пересмотра стандарта): Однако, если дано, вы можете сделать это:

template <> template <> Foo<1> Bar<1>;

Но не в том случае, если Фу не специализируется в первую очередь.

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