ограничение специализаций с использованием SFINAE, ограничений или концепций?

Следующая программа работает нормально:

struct M; // forward declare so compiler will recognize this type
struct N;

template< typename J > struct B { template< typename U > void Func1(); };

template<> template<> void B< M >::Func1< M >() {}
template<> template<> void B< N >::Func1< N >() {}
template<> template<> void B< M >::Func1< N >() {} // illegal specialization for this app

template< typename J > struct C { template< typename U > void Func2(); };

template<> template<> void C< M >::Func2< M >() {}
template<> template<> void C< N >::Func2< N >() {}

template< typename G > struct H { G g; };

int main()
{
  H< B< M > > hbm;
  hbm.g.Func1< M >(); // ok
  hbm.g.Func1< N >(); // compiles and runs, but uses a semantically illegal specialization for this app

  H< B< N > > hbn;
  hbn.g.Func1< N >(); // ok

  H< C< M > > hcm;
  hcm.g.Func2< M >(); // ok

  H< C< N > > hcn;
  hcn.g.Func2< N >(); // ok

  return 0;
}

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

Но, как видно из приведенного выше кода, мои последующие разработчики (когда-нибудь!) Могут создавать синтаксически правильные шаблоны, которые не имеют смысла семантически. В частности, приложение знает только, как использовать типы, у которых типы классов и функций равны. Остальное бессмысленно.

Это похоже на случай одной из новых возможностей C ++ 17 +, таких как SFINAE, Ограничения или Концепции. Хотя я читаю об этом, у меня еще нет решения, чтобы сделать такой выбор. В cppreference в разделе «Альтернативы» они предлагают концепции вместо SFINAE, если компилятор поддерживает эту возможность (я использую VS2015).

Что было бы хорошим способом ограничить typename J таким же, как typename U?


person rtischer8277    schedule 24.05.2016    source источник
comment
SFINAE не новичок в C ++. По сути, ограничения - это то же самое, что и концепции.   -  person Nicol Bolas    schedule 24.05.2016
comment
Вы понимаете, что концепции не являются частью C ++ 17?   -  person SergeyA    schedule 24.05.2016
comment
typename = std::enable_if_t<std::is_same<U,J>{}> в списке параметров шаблона должно быть достаточно   -  person Piotr Skotnicki    schedule 24.05.2016
comment
@PiotrSkotnicki Этого некуда поставить, сохраните сами специализации (хотя желательно в форме утверждения, конечно). Но затем, если программист будет достаточно осторожен, чтобы написать утверждение, то, по-видимому, он будет столь же осторожен, чтобы не писать неправильные специализации с самого начала.   -  person Luc Danton    schedule 24.05.2016
comment
@LucDanton, если вы не специализируетесь на втором параметре шаблона по умолчанию, каждая специализация также использует его по умолчанию   -  person Piotr Skotnicki    schedule 24.05.2016
comment
Почему у вас вообще есть отдельный параметр шаблона, если они все равно должны быть одного типа?   -  person T.C.    schedule 24.05.2016
comment
Почему у вас вообще есть отдельный параметр шаблона, если они все равно должны быть одного типа? Т.К .: Я не мог понять. Однако объявление .h вводит информацию только один раз. Я не мог обойтись без шаблонов классов B и C, хотя, читая, я мог видеть, что были некоторые конструкции специализации, которые выглядели как ‹T :: B› или ‹T :: C›.   -  person rtischer8277    schedule 25.05.2016
comment
Вы понимаете, что концепции не являются частью C ++ 17? - SergeyA Да, я знаю, но сегодня я достаточно уверен, что Microsoft перешла на современный C ++, поэтому я не против включения новых конструкций в свой производственный код 1.0. Будущие изменения синтаксиса выполнимы, но будущие повторные записи - нет. Эти конструкции в целом превратили мой разрастающийся, экспоненциально увеличивающийся в размерах и необслуживаемый код прототипа в легко поддерживаемый код. Хорошая работа, ребята из ISO C ++.   -  person rtischer8277    schedule 25.05.2016
comment
@ T.C. Нет необходимости дублировать параметры шаблона, как вы предполагали, как в случае с исходным кодом: A< D, B< D > > a1; и A< E, C< E > > a2;. Использованной конструкцией были «шаблоны шаблонов», на которые указал @skypjack в ссылке.   -  person rtischer8277    schedule 01.06.2016


Ответы (1)


Вы можете использовать enable_if:

template< typename J > struct B {     
    template<typename U>
    typename std::enable_if<std::is_same<U, J>::value, void>::type
    Func1();
};

http://coliru.stacked-crooked.com/a/efb499cf654f0f25

С концепциями (не в стандарте в ближайшем (?) Будущем) то же решение, что и выше, будет выглядеть так, как показано ниже.

http://melpon.org/wandbox/permlink/li4Uh5Q6ilpnlhcl

template <class T, class U> concept bool Same = std::is_same<T,U>::value;

template< typename J > struct B { 
    template< typename U > 
    requires Same<J, U>    
    void Func1(); 
};
person marcinj    schedule 24.05.2016
comment
Нет, так нельзя. аргументы шаблона по умолчанию не являются частью сигнатуры функции. - person SergeyA; 24.05.2016
comment
Это одна из тех ситуаций Макиавелли против Мерфи, и каждый решает, если это любая помощь. - person Luc Danton; 24.05.2016
comment
@SergeyA, вы имеете в виду, что я должен скопировать параметр шаблона J, как здесь: template ‹typename U, typename J2 = J, typename = std :: enable_if_t‹ std :: is_same ‹J2, U› :: value ››? - person marcinj; 24.05.2016
comment
@marcinj, мне нужно забрать обратно. Вы не собираетесь создавать еще одну перегрузку Func1 в B, вы просто отключите единственный Func1. Ваш код в порядке. - person SergeyA; 24.05.2016
comment
Другой пример, который, возможно, больше Мерфи и меньше Макиавелли, где потенциально ошибочный программист специализируется на шаблон класса перед шаблоном функции. - person Luc Danton; 24.05.2016
comment
Для немного большей защиты от Макиавелли поместите enable_if в возвращаемый тип. - person T.C.; 24.05.2016
comment
@marcinj Ваше шаблонное решение компилируется и запускается с использованием VS2015 с обновлением 2, но ваше решение Concepts должно быть помещено в код в качестве комментария, пока VS2015 не реализует Concepts. - person rtischer8277; 25.05.2016