Шаблон класса C++ с параметром, отличным от типа, в зависимости от проблемы с параметром типа с использованием C++11

Я понимаю, что обычные средства в С++ для контроля во время компиляции того, какие функции-члены шаблона класса включаются/исключаются, осуществляются посредством частичной специализации. У меня есть шаблон класса, который имеет параметр типа и параметр, не являющийся типом, в зависимости от параметра типа. Когда параметр нетипа имеет определенное значение, я хочу, чтобы определенные функции-члены шаблона класса были частью создания экземпляра шаблона класса, но не другие. Обычный способ сделать это — закодировать основной шаблон, включив в него определенные функции-члены, а затем закодировать частичную специализацию основного шаблона с другим набором функций-членов. Но из-за правила, которое гласит:

Аргумент шаблона, не являющийся типом, не может специализировать параметр шаблона, тип которого зависит от параметра специализации. Я не могу этого сделать. Это можно обойти ? Простой пример кода будет выглядеть так:

  template 
    <
    class T, 
    T * v
    >
  struct  AClassTemple
    {
    void SomeMemberFunction() { code etc. }
    void AnotherMemberFunction() { code etc. }
    };

Когда 'v' является nullptr, я хочу, чтобы мой шаблон класса не включал AnotherMemberFunction и ее код, который предполагает значение для 'v', которое не является nullptr. Я не могу частично специализировать шаблон класса, указав:

  template 
    <
    class T 
    >
  struct  AClassTemple<T,nullptr>
     {
     };

и т. д., иначе я получаю ошибку компилятора, отражающую указанное выше правило.


person Edward Diener    schedule 03.02.2021    source источник
comment
М-м-м. Является ли v nullptr или нет, может быть неизвестно во время компиляции...   -  person Enlico    schedule 03.02.2021
comment
Является ли v nullptr или нет, всегда известно во время компиляции. Когда конечный пользователь создает экземпляр шаблона класса, он либо передает nullptr в качестве аргумента второму параметру шаблона, либо нет. Параметр шаблона, не являющийся типом, всегда является значением времени компиляции.   -  person Edward Diener    schedule 04.02.2021
comment
Вот что я имею в виду. Я имею в виду следующее: если конечный пользователь должен вручную написать AClassTemplate<sometype,nullptr> или AClassTemplate<sometype,non_null_ptr>, чтобы выбрать два случая, почему бы вам не заставить его просто написать ClassTemplateA<sometype> и ClassTemplateB<sometype>? В чем преимущество использования параметра шаблона, отличного от типа, для различения двух случаев, если этот параметр нельзя вывести? Однако, если вы знаете, что этот параметр известен во время компиляции, то полученный вами ответ помогает.   -  person Enlico    schedule 04.02.2021


Ответы (1)


Следующее должно делать то, что вы хотите:

#include <type_traits>

template<class T, T *v>
struct AClassTemple {
    template<T *w = v, class = std::enable_if_t<w != nullptr>>
    void SomeMemberFunction() {}

    template<T *w = v, class = std::enable_if_t<w != nullptr>>
    void AnotherMemberFunction() {}
};

int main() {
    constexpr static char c = '0';
    AClassTemple<int, nullptr> a{};
    AClassTemple<const char, &c> b{};

    // a.SomeMemberFunction(); // will not compile
    b.SomeMemberFunction();
}
person n314159    schedule 03.02.2021
comment
Исходя из того, как поставлен вопрос, я бы подчеркнул следующее, даже если это очевидно: это решение (и вообще любое решение) работает только в том случае, если вы передаете постоянное выражение (такое как литерал nullptr или переменная constexpr) как не аргумент типа. Например, выполнение int * x = nullptr; AClassTemple<int, x> a{}; не сработает. - person Enlico; 03.02.2021