Можно ли установить разные модификаторы доступа для специализаций шаблонов членов класса (и членов шаблонов классов)?

  1. Можно ли установить разные модификаторы доступа для специализаций шаблонов членов класса? Пример кода (не компилируется):

    class SimpleClass
    {
    public:
    template <typename T>
    void Method();
    template <>
    void Method<char>();
    protected:
    template <>
    void Method<int>();
    protected:
    template <>
    void Method<float>();
    };
    
    • Вопрос: возможно ли установить разные модификаторы доступа для специализаций конструктора шаблонов класса? Пример кода (не компилируется):

      class SimpleClass
      {
      public:
      template <typename T>
      SimpleClass(T);
      template <>
      SimpleClass<char>(char);
      protected:
      template <>
      SimpleClass<int>(int);
      private:
      template <>
      SimpleClass<float>(float);
      };
      
  2. Можно ли установить разные модификаторы доступа для специализаций членов шаблона класса? Пример кода (не компилируется):

    template <typename T>
    class ClassTemplate
    {
    public:
    void Method();
    template <>
    void Method<char>();
    protected:
    template <>
    void Method<int>();
    protected:
    template <>
    void Method<float>();
    };
    
    • Вопрос: возможно ли установить разные модификаторы доступа для специализаций конструктора шаблона класса? Пример кода (не компилируется):

      template <typename T>
      class ClassTemplate
      {
      public:
      ClassTemplate(T);
      template <>
      ClassTemplate<char>(char);
      protected:
      template <>
      ClassTemplate<int>(int);
      private:
      template <>
      ClassTemplate<float>(float);
      };
      

Чтобы быть более конкретным: в 1) Я ищу обходной путь C ++ 03 для такого кода C ++ 11:

class SimpleClass
{
public:
template <typename T>
SimpleClass(T);

template <typename T>
void Method();
};

template <>
SimpleClass::SimpleClass<char>(char);
template <>
SimpleClass::SimpleClass<int>(int) = delete;

template <>
void SimpleClass::Method<char>();
template <>
void SimpleClass::Method<int>() = delete;

В 2) Я ищу обходной путь C ++ 03 для следующего кода C ++ 11:

template <typename T>
class ClassTemplate
{
public:
ClassTemplate(T);

void Method();
};

template <>
ClassTemplate<char>::ClassTemplate(char);
template <>
ClassTemplate<int>::ClassTemplate(int) = delete;

template <>
void ClassTemplate<char>::Method();
template <>
void ClassTemplate<int>::Method() = delete;

3

Решение

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

template <bool C, typename T = void>
using only_if = typename std::enable_if <C, T>::type;

template <typename A, typename B>
using eq = typename std::is_same <A, B>::type;

class SimpleClass1
{
public:
template <typename T, only_if <!eq <T, int>{} && !eq <T, float>{}, int> = 0>
SimpleClass1() { }
protected:
template <typename T, only_if <eq <T, int>{}, int> = 0>
SimpleClass1() { }
protected:
template <typename T, only_if <eq <T, float>{}, int> = 0>
SimpleClass1() { }
};

class SimpleClass2
{
public:
template <typename T, only_if <!eq <T, int>{} && !eq <T, float>{}, int> = 0>
SimpleClass2(T) { }
protected:
template <typename T, only_if <eq <T, int>{}, int> = 0>
SimpleClass2(T) { }
private:
template <typename T, only_if <eq <T, float>{}, int> = 0>
SimpleClass2(T) { }
};

template <typename T>
class ClassTemplate1
{
public:
template <typename U, only_if <!eq <U, int>{} && !eq <U, float>{}, int> = 0>
void Method() { }
protected:
template <typename U, only_if <eq <U, int>{}, int> = 0>
void Method() { }
protected:
template <typename U, only_if <eq <U, float>{}, int> = 0>
void Method() { }
};

template <typename T>
class ClassTemplate2
{
public:
template <typename U, only_if <!eq <U, int>{} && !eq <U, float>{}, int> = 0>
void Method(U) { }
protected:
template <typename U, only_if <eq <U, int>{}, int> = 0>
void Method(U) { }
protected:
template <typename U, only_if <eq <U, float>{}, int> = 0>
void Method(U) { }
};

Я не знаю, где все это было бы полезно 🙂 В любом случае:

  • Я старался сделать все перегрузки конструктора / метода взаимоисключающими, чтобы избежать неоднозначностей и проблем с различными спецификаторами доступа, что может быть сложно. Это затрудняет обобщение на большее количество типов. Псевдоним шаблона поможет в общем случае / случае по умолчанию (который является дополнением ко всем остальным).

  • Однако это не совсем то, что вы описали в вопросе. Эти методы обеспечивают строгое равенство типов, поэтому не допускают неявных преобразований. Вы могли бы попробовать std::is_convertible вместо этого, но тогда вы открываете дверь для неясностей.

  • Весь код компилируется как таковой, но я на самом деле не пытался использовать классы, поэтому я не знаю, что может произойти.

  • Я действительно не знаю, как можно использовать SimpleClass1: Как мы можем явно указать аргумент шаблона для конструктора по умолчанию (поскольку он не может быть выведен)?

  • Глядя на код еще раз, я думаю, что ClassTemplate не сильно отличается (или вообще) от SimpleClass, ClassTemplate1 не может иметь аргумент шаблона по умолчанию, потому что это было бы неоднозначно.

2

Другие решения

Мы можем сделать это с SFINAE, но, к сожалению, нам нужно is_same а также enable_if, к счастью, ни один из них не требует никакого языка C ++ 11! Таким образом, мы можем просто ввести их реализации для наших собственных нужд:

template <typename A, typename B>
struct is_same {
static const bool value = false;
};

template<typename A>
struct is_same <A, A> {
static const bool value = true;
};

template<bool B, class T = void>
struct enable_if {};

template<class T>
struct enable_if<true, T> { typedef T type; };

Далее мы объединяем их, используя enable_if «SFINAE удалить» методы, которые вы не хотите. Конструктор / метод шаблона нуждается в трюке. Нам нужно, чтобы первый аргумент был типом для вывода аргумента. Мы добавляем второй, фиктивный аргумент с единственной целью удаления метода, если тип не поддерживается вами. Вы можете добавить перегрузки для большего количества типов, если вам нужно. За Method() мы можем снова применить фиктивный аргумент, и T будет дано явно, поэтому нет необходимости в каких-либо вычетах:

class SimpleClassConstructor {
public:
template <typename T>
SimpleClassConstructor(T value,
typename enable_if<is_same<T, char>::value, T>::type enabler = 0) {
}
template <typename T>
void Method(typename enable_if<is_same<T, char>::value, T>::type enabler = 0) {
}
};

Для класса шаблона ~~ мы можем использовать точно такую ​​же методологию, но мы можем использовать результат enable_if непосредственно, так как нам не требуется выведение аргументов. ~~ Чтобы удовлетворить требования, касающиеся конкретного удаления методов, мы можем переместить enable_if Методология для параметра шаблона. Это позволит SFINAE мягко удалить метод (вместо того, чтобы отключить весь класс, если enable_if терпит неудачу):

template <typename T>
class SimpleClassTemplate {
public:
template <typename Enable = enable_if<is_same<T, char>::value, T>::type>
SimpleClassTemplate(T value) {

}
};

Для теста попробуйте это:

int main() {
char a = 0;
SimpleClassTemplate<char> A1(a); // OK
SimpleClassConstructor A2(a); // OK

A2.Method<char>(); // OK
A2.Method<int>(); // compilation error!

int b = 0;
SimpleClassTemplate<int> B1(b); // compilaton error!
SimpleClassConstructor B2(b); // compilation error!
}
3

Для конструктора или метода по умолчанию без входных параметров, я думаю, что ответ на Специализация шаблона в определении класса достаточно. Он использует только std::enable_if а также std::is_same, которые легко определить.

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

template <bool C, typename T = void>
using only_if = typename std::enable_if <C, T>::type;

template <typename A, typename B>
using eq = typename std::is_same <A, B>::type;

class SimpleClass {
public:
template <typename T, only_if <!eq <T, int>{}, int> = 0>
SimpleClass(T) { ... }

template <typename T, only_if <!eq <T, int>{}, int> = 0>
void Method(T) { ... }
// ...
};
2

Попробуйте использовать «Шаблон специализации»:

template <typename T>
struct S {
void foo();
void bar();
};

template <>
struct S<int> {
void foo();
};int main()
{
S<char> sc;
sc.foo();
sc.bar();

S<int> si;
si.foo();
si.bar(); // compile error: 'bar' : is not a member of 'S<int>'

}
0
По вопросам рекламы [email protected]