LINUX.ORG.RU

[C++] Специализация шаблонов

 


0

1
template<typename T,bool XXX>
class foo{
 public:
  ...
  void bar();
  ...
};

template<typename T,bool XXX>
void foo<T,XXX>::bar(){...}

//хочу специализировать метод bar для XXX=true
template<typename T,bool XXX>
template<T>foo<T,true>::bar(){...}
//error: invalid use of incomplete type ‘class foo<T, true>’

Как правильно специализировать bar? Целиком специализировать весь класс - это тонна копипасты. Гуглится всякая муть...

★★★★★

Последнее исправление: staseg (всего исправлений: 1)

Это по моему называется частичная спецификация (специализация?).

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

Если не хочется копипастить - подумайте над наследованием? Общий предок, и при спецификации наследуетесь от него и изменяете те методы, к-е нужны.

AIv ★★★★★
()

специлизируется не функция, специлизируется шаблон, соответственно Вам необходимо повесить шаблон на функцию и завязать его с «bool XXX», а там уже параметризовать пока батарейки не кончатся

shty ★★★★★
()
Ответ на: комментарий от anonymous

Честно говоря не очень понял идею. Ты имеешь в виду перегрузить два метода

void bar(<struct smth<true> >)
void bar(<struct smth<false> >)
? Тогда как этим пользоваться? Мне нужно, чтобы было так:
foo<int,true>a;
foo<int,false>b;

a.bar();//тут
b.bar();//и тут вызываются два разных bar

За пример кода буду вдвойне признателен.

staseg ★★★★★
() автор топика
Ответ на: комментарий от anonymous

> зато есть структуры, которые могут быть параметрами

Можно конечно ввести структуры TRUE и FALSE (и даже myfinger<bool XXX>) и перегружать методы в заивисмости от XXX, но это неск не то - реализация для true может быть несовместима с реализацией для false (ну там разные наборы полей в классе, методы с разными сигнатурами и проч). Хотя это конечно менее геморно чем наследоваться.

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

Где меньше писанины сходу трудно сказать, от конкретики зависит.

AIv ★★★★★
()
Ответ на: комментарий от shty

>специлизируется не функция, специлизируется шаблон, соответственно Вам необходимо повесить шаблон на функцию и завязать его с «bool XXX», а там уже параметризовать пока батарейки не кончатся

Спасибо за идею. Сейчас попробую наколдовать чего-нибудь.

staseg ★★★★★
() автор топика
Ответ на: комментарий от KblCb

>У тебя есть класс под названием true?

Специализировать шаблоны можно не только типами, но и значениями (собственно, на этом и основаны всякие mpl::if_, enable_if и факториалы на этапе компиляции)

yoghurt ★★★★★
()
Ответ на: комментарий от shty
template<bool X>
class suxx{
public:
 static void foo(){
  printf("foo false\n");}
};

template<>
class suxx<true>{
public:
 static void foo(){
  printf("foo true\n");}
};


template<typename T,bool XXX>
class X{
public:
 void foo(){
  suxx<XXX>::foo();}
};

Сделал так. Выглядит чудовищно монстроузно :(

staseg ★★★★★
() автор топика
Ответ на: комментарий от staseg

Сделал так. Выглядит чудовищно монстроузно

1. зато работает
2. потом привыкнете
3. решайте задачу красиво архитектурно

shty ★★★★★
()
Ответ на: комментарий от staseg
#include <iostream>
using namespace std;

template<bool> struct  SB;
template<> struct SB<true>{};
template<> struct SB<false>{};

template <typename T, bool X>
class A
{

	void f(SB<true>){cout << "true" << endl;}
	void f(SB<false>){cout << "false" << endl;}
public:
	void f() { f( SB<X>() ); }
};

int main(int, char*)
{
	A<double, true> at;
	A<double, false> af;
	at.f();
	af.f();
	return 0;
}
anonymous
()
Ответ на: комментарий от staseg
template<bool XXX> class TF{};

void foo(TF<true>){ ... }
void foo(TF<false>){ ... }


template <class T, bool XXX> class X{
...
 void foo(){ ::foo(TF<XXX>()); }

}; 

А так?

AIv ★★★★★
()
Ответ на: комментарий от anonymous

SB можно не специализировать, и f(SB) лучше ИМНО таки сделать внешними - реализация с true может оказаться неинстанцируемой в классе с false. Хотя ее может и не проинстанцировать.

AIv ★★★★★
()
Ответ на: комментарий от anonymous

Во! Это самое то, что надо. Намного меньше монстроузности. Спасибо большое.

staseg ★★★★★
() автор топика
Ответ на: комментарий от AIv

>f(SB) лучше ИМНО таки сделать внешними

А как же мне из внешней f обращаться к своим объектам?

staseg ★★★★★
() автор топика
Ответ на: комментарий от staseg

Да, в своем suxx-варианте я тоже не могу этого делать, только что заметил :)

staseg ★★★★★
() автор топика
Ответ на: комментарий от staseg

> Сделал так. Выглядит чудовищно монстроузно :(

СО статик методами завсегда так... зато в каждый класс можно завернуть несколько методов, тогда это уже будет вполне осмысленно. Но перегрузка ИМНО все же поизящней.

AIv ★★★★★
()
Ответ на: комментарий от staseg

Если реализации не кофликутют - не делайте внешними. Если конфликтуют - вышеп уже писал, свой объект первым аргументом передаете по ссылке, при необх. ф-ии делаете friend.

AIv ★★★★★
()
Ответ на: комментарий от AIv

Блин, мудрецы!;-)

template <class T,bool XXX> class X;

template<class T> void foo(X<T,true>& self){...}
template<class T> void foo(X<T,false>& self){...}

template<class T,bool XXX> class X{
...
void foo(){ ::foo(*this); }
};

AIv ★★★★★
()
Ответ на: комментарий от AIv

Да, все, я сообразил. Всем большое спасибо запомощь!

staseg ★★★★★
() автор топика
Ответ на: комментарий от AIv

Вообще красота!

Премного благодарен :)

staseg ★★★★★
() автор топика
Ответ на: комментарий от AIv

>Если реализации не кофликутют - не делайте внешними. Если конфликтуют - вышеп уже писал, свой объект первым аргументом передаете по ссылке, при необх. ф-ии делаете friend.

http://www.gotw.ca/gotw/084.htm

Там раздел 3 «Membership Has Its Rewards — and Its Costs» — хорошие соображения про то, когда функции делать членом или нет, другом или нет.

anonymous
()
Ответ на: комментарий от staseg

я бы сделал так:

#include <iostream>

template<int v>
struct Int2Type {
	enum { value = v };
};

template<bool flag>
class Foo {
private:
	void bar(Int2Type<true>) {
		std::cout << "true bar" << std::endl;
	}

	void bar(Int2Type<false>) {
		std::cout << "false bar" << std::endl;
	}

public:
	void bar() {
		bar(Int2Type<flag>());
	}

};

int main() {
	Foo<true> ft;
	ft.bar();
	return 0;
}
shty ★★★★★
()

Это конечно все хорошо но if(expr) { foo } else { bar } соотвествуют KISS и умный компилятор _fn(true) заменит на foo. Надо проклинать Loki зато что он ввел в моду эти костыли. Помните. Компилятор и сам по максимальному вычисляет все выражения и инлайнит. Шаблоно костыли со специализациями для этого не нужны, простите не банальность.

bga_ ★★★★
()
Ответ на: комментарий от bga_

Ты не поверишь, я именно так и сделал :)

Но вопрос запостил с целью расширения кругозора - как собственно нормально специализировать один метод класса в общем случае. Тоже не люблю хаки с темплейтами и обхожу буст с локи за километр.

staseg ★★★★★
() автор топика
Ответ на: комментарий от bga_

Это конечно все хорошо но if(expr) { foo } else { bar } соотвествуют KISS и умный компилятор _fn(true) заменит на foo.

неплохо бы ещё и пруф увидеть, и обоснование что во всех ситуациях это будет именно так

shty ★★★★★
()
Ответ на: комментарий от staseg

Но вопрос запостил с целью расширения кругозора [..]
не люблю хаки с темплейтами и обхожу буст с локи за километр.

ну-ну, ходите-ходите

shty ★★★★★
()
Ответ на: комментарий от anonymous

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

template<class f>
struct o
{
y(int2type<true>){}
y(int2type<false>)
{puts(7777);}
void z()
{
 y(int2type<f>());
}
};

...
o<true>().z();
все компилится а стоит поменять true на false все сломается

anonymous
()
Ответ на: комментарий от shty

>неплохо бы ещё и пруф увидеть, и обоснование что во всех ситуациях это будет именно так

Компилятор всегда старается вычислить все константы, что только можно, на этапе компиляции. Это в общем-то известный и очевидный факт. Пруфы я искать не буду, посмотри ассемблерные выхлопы. Всякие if(true), 1+2 не попадают в исполняемый код.

staseg ★★★★★
() автор топика
Ответ на: комментарий от shty

Даже если это не так для какого то семейства компиляторов то впору править компилятор а не воротить костыли.

bga_ ★★★★
()
Ответ на: комментарий от anonymous

там не только int2type там еще такая вкусняшка как LOKI_ON_BLOCK_EXIT есть это из того чем я пользуюсь а так там много полезного

anonymous
()
Ответ на: комментарий от bga_

Лично мне класс A нравится больше, чем класс A2 с его switch.
Класс A с перегрузкой для меня больший KISS.

#include <iostream>
using namespace std;

enum E { a, b, c, d } ;

template<E> struct  SB{};

template <typename T, E X>
class A
{
	T m_value;
	void f(SB<a>){cout << "a " << m_value << endl;}
	void f(SB<b>){cout << "b " << m_value << endl;}
	void f(SB<c>){cout << "c " << m_value << endl;}
	void f(SB<d>){cout << "d " << m_value << endl;}
public:
	A(T value) : m_value(value) {}

	void f() { f( SB<X>() ); }
};

template <typename T, E X>
class A2
{
	T m_value;
	void f_a(){cout << "a " << m_value <<  endl;}
	void f_b(){cout << "b " << m_value << endl;}
	void f_c(){cout << "c " << m_value << endl;}
	void f_d(){cout << "d " << m_value << endl;}
public:
	A2(T value) : m_value(value) {}

	void f() 
	{
		switch (X) 
		{
			case a: f_a();break;
			case b: f_b();break;
			case c: f_c();break;
			case d: f_d();break;
		}
	}
};

int main(int, char*)
{
	A<double, a> aa(1); A<double, b> ab(1); A<double, c> ac(1); A<double, d> ad(1);
	aa.f(); ab.f(); ac.f(); ad.f();
	cout << endl;
	A2<double, a> a2a(2); A2<double, b> a2b(2); A2<double, c> a2c(2); A2<double, d> a2d(2);
	a2a.f(); a2b.f(); a2c.f(); a2d.f();
	return 0;
}

anonymous
()
Ответ на: комментарий от anonymous

Тут вообще константный массив указателей на функции хорошо бы и енум упорядоченный. И в рантайме диспечеризация и в компилетайме.

bga_ ★★★★
()
Ответ на: комментарий от anonymous

> что удивительно что выражение даже может быть семантически некорректное компилятор проглотит код и все скомпилирует

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

AIv ★★★★★
()

А может не надо?

сабж

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

pathfinder ★★★★
()
Ответ на: Меян, это тыф от anonymous

Здорово! <личная переписка. сорри>

>staseg, а как с Вами можно связаться? Джаббер/Skype?

Пиши на mailto: staseg at tvernet.ru. Там разберемся.

staseg ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.