2010-05-29 9 views
3
template <typename X, typename Y> class A { 
    // Use Y::Q, a useful property, not used for specialization. 
}; 
enum Property {P1,P2}; 
template <Property P> class B {}; 
class C {}; 

Есть ли способ определить частичную специализацию A таким образом, что A<C, B<P1> > будет A «s нормальный шаблон, но A<C, B<P2> > будет специализация?Частичная специализация шаблона: соответствие по свойствам специализированного параметра шаблона

Редактировать в ответ на Marcelo: В частности, специализацию следует выбирать не только с помощью B, но и с любым типом, который обладает определенным свойством, например, что это шаблон, первым аргументом которого является P2.

Цель состоит в том, чтобы использовать Y, чтобы представить приятный интерфейс для A, что позволяет написать что-то вроде A<C, Y<P2,Q> >.


Замена параметр Y шаблона с помощью параметра шаблона шаблона был бы хорошо, но есть способ частично специализируется он основан на P тогда?

Намерение было бы написать что-то вроде:

template <typename X, template <Property P> typename Y> class A {}; 
template <typename X> class A<X,template<> Y<P2> > {}; // <-- not valid 

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


Есть ли способ, добавив черты к специализации template <> class B<P2>, а затем с помощью SFINAE в A? Намерение было бы написать что-то вроде:

template <> class B<P2> { 
    typedef int IAmP2; 
}; 

// The following is not valid because it's a simple redefinition. 
template <typename X, typename Y> class A { 
    // Substitution using this template would fail for Y<P1>, and only the 
    // general template would be left for selection. 
    typename Y::IAmP2 skipIfNotP2; 
}; 
+0

Что вы пытаетесь сделать конкретно? Вероятно, вы можете достичь того, чего хотите, но я не совсем понимаю ваш вопрос. Что означают 'X' и' Y' в вашем предполагаемом приложении? –

+0

Кстати, SFINAE работает только для функциональных перегрузок, а не для специализированных шаблонов. –

+0

Предположим, у вас есть Matrix , и вы хотите сделать что-то вроде Matrix > или Matrix >, но вам нужна специализированная версия матрицы для всех плотных схем хранения. – Kenzo

ответ

4

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

template <typename X, typename Y> 
class A { 
}; 

template <typename X, template<typename> class Y, typename P> 
class A< X, Y<P> > { 
    /* property is P */ 
}; 

Для вашего SFINAE вопрос, да, что это тоже возможно

template <typename X, typename Y, typename Sfinae = void> 
class A { 
}; 

template <typename X, typename Y> 
class A< X, Y, typename Y::IAmP2 > { 
    /* Y is the class having a property */ 
}; 

class Sample { 
    typedef void IAmP2; 
}; 

Тем не менее я не уверен, что вы имеете в виду вообще.

+0

Большое спасибо Йоханнесу. Оба ваших предложения (шаблон шаблона и SFINAE) находятся на месте. Это именно тот механизм, который я искал, но я не мог понять синтаксис. Для решения шаблона шаблона расширение списка параметров шаблона - это то, что я наблюдал (читал об этом один раз, но не помнил). В конце концов, однако, я буду использовать решение SFINAE, которое более гибко, поскольку оно не требует, чтобы я объявлял фиксированное количество параметров шаблона шаблона. Снова благодарим кучу, сегодня узнали :). – Kenzo

0

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

template <> class A<C, B<P2> > { ... }; 

Слишком просто, на самом деле. Мне что-то не хватает, но я не вижу, что.

+0

Спасибо за наш ответ Марсело. Цель состоит в том, чтобы эта специализация по шаблону применялась не только к B , но и к любому типу Y . На самом деле, желая, чтобы P2 являлось отличительным свойством типов, удовлетворяющих этой специализации, является просто * * * способом сделать их разными. Я гибкий в этой части. Суть заключается в том, чтобы определить, есть ли возможность частичной специализированности шаблонов, сопоставленной при создании экземпляра, по более общим мета-свойствам/чертам типов, чем только их имена. – Kenzo

0

Это то, что вы хотите? (Испытано с Visual Studio 2005)

enum Property { P1, P2 }; 

template <Property P> class B {}; 
class C {}; 

// Other similar types, for the purpose of testing 
template <Property P> class AnotherB {}; 
class AnotherC {}; 

// Primary template 
template <typename X, template<Property P> class Y, Property P> class A 
{ 
public: 
    A() { ::printf("Primary template\n"); } 
}; 

// Partial specialization for P2 
template <typename X, template<Property P> class Y> class A<X, Y, P2> 
{ 
public: 
    A() { ::printf("Partially specialized template\n"); } 
}; 

int main() 
{ 
    // Trying out some combinations 
    A<C, B, P1> q;    // prints "Primary template" 
    A<C, B, P2> w;    // prints "Partially specialized template" 
    A<AnotherC, B, P1> e;  // prints "Primary template" 
    A<AnotherC, B, P2> r;  // prints "Partially specialized template" 
    A<C, AnotherB, P1> t;  // prints "Primary template" 
    A<C, AnotherB, P2> y;  // prints "Partially specialized template" 
    A<AnotherC, AnotherB, P1> u; // prints "Primary template" 
    A<AnotherC, AnotherB, P2> i; // prints "Partially specialized template" 
} 

Ваша попытка частичной специализации приводит к ошибкам компиляции, потому что вы можете передать только шаблоны для шаблона параметров шаблона. Вы не можете пройти в template <> class B<P2> для параметра шаблона шаблона, потому что это полный тип, а не шаблон.

Для первых двух строк кода в функции main(), C полный тип мы проходим, чтобы A «s типа параметр X. B является шаблон, который мы передаем в 's шаблона параметр Y, и этот шаблон должен принять Property как единственный параметр шаблона.Мы передаем значение Property (либо P1, либо P2) на Anontype параметр P отдельно. Когда мы перейдем к P2 для последнего аргумента шаблона A, компилятор увидит специализацию и будет использовать это - иначе компилятор будет использовать основной шаблон A. Аналогичная картина следует для следующих 6 строк.

+0

Спасибо за ваш ответ В силико, это проницательно, но все же не то, что я искал (моя вина). Я сказал в вопросе, что было бы неплохо сделать Y параметром шаблона шаблона, но на самом деле это не так. Я отредактировал вопрос, чтобы сделать его более ясным. – Kenzo

+0

Я мог бы использовать шаблон шаблона шаблона для достижения того, что хочу, но для этого потребуется изменить типичный вызов от A > до A , P2>, который 1) побеждает цель приятного интерфейса. 2) требует механизм проверки того, что первый параметр B такой же, как и третий параметр A. Еще раз спасибо, приветствия. – Kenzo

+0

Опять же, это не работает, потому что 'B ' - это полный тип, который вы не можете передать шаблону шаблона. Просто перейдите в 'B' к параметру шаблона шаблона' A' и поставьте 'P2' и' Q' отдельно. Таким образом, у вас будет что-то вроде 'A '. Таким образом, вы не дублируете 'P2', одновременно решаете проблемы (1) и (2).Если я действительно не знаю, чего ты хочешь. :-) –

0

Я дам еще один ответ в ответ на ваш комментарий с примером Matrix.

Для вашего Matrix Например, вы можете сделать это:

enum MatrixOrder { ColumnMajor, RowMajor }; 

template<MatrixOrder Order> class Dense {}; 
template<MatrixOrder Order> class Sparse {}; 

template<typename T, template<MatrixOrder> class Storage, MatrixOrder Order> 
class Matrix 
{ 
public: 
    Matrix() { ::printf("Primary\n"); } 
}; 

template<typename T, MatrixOrder Order> 
class Matrix<T, Dense, Order> 
{ 
public: 
    Matrix() { ::printf("Specialized\n"); } 
}; 

int main() 
{ 
    // Trying out some combinations... 
    Matrix<double, Dense, ColumnMajor> a; // Prints "Specialized" 
    Matrix<double, Dense, RowMajor> b;  // Prints "Specialized" 
    Matrix<double, Sparse, ColumnMajor> c; // Prints "Primary" 
    Matrix<double, Sparse, RowMajor> d; // Prints "Primary" 
    Matrix<float, Dense, ColumnMajor> e; // Prints "Specialized" 
    Matrix<float, Dense, RowMajor> f;  // Prints "Specialized" 
    Matrix<float, Sparse, ColumnMajor> g; // Prints "Primary" 
    Matrix<float, Sparse, RowMajor> h;  // Prints "Primary" 
    return 0; 
}; 

Он принимает на аналогичной схеме на мой последний ответ. Теперь все специализированные схемы хранения, взяв на себя Dense. Надеюсь, это поможет, по крайней мере, немного. :-)

+0

Он работает очень хорошо, но является своего рода резервным решением, если более приятный интерфейс невозможен, поскольку он выравнивает все параметры до одного уровня без логической группировки. Требуемый интерфейс может выполнять: Matrix , 640,480>. С предлагаемым интерфейсом: 1) мне нужно сделать Matrix , RowMajor, 640 480>, который еще длиннее 2) Я также могу сделать Matrix , RowMajor, 640,480>, который имеет семантическое несоответствие для решения линейной индексации. – Kenzo

+0

И эти проблемы усиливаются с большим количеством параметров. Причина, по которой мне было интересно, можно ли было выполнить эту группировку параметров шаблона, выглядит следующим образом: Матрица , Оптимизация <Векторизация, Развертывание, Lazy>>. По умолчанию, конечно, нужно просто сгладить все это до Matrix , но это не очень приятно в том смысле, что оно смешивает все, и я не могу предварительно настроить схемы хранения независимо, которые могут быть просто переданы в качестве шаблонных аргументов. Какой-то крайний пример, я думаю. – Kenzo

+0

Ах, я думаю, я вижу, где это происходит. Похоже, что вам нужен какой-то шаблон политики (см. Http://en.wikipedia.org/wiki/Policy-based_design). «Хранение» и «Оптимизация» могут быть классами политики, которые диктуют поведение «Матрицы», предоставляя «части» функциональности «Матрице». –