Как сделать генерацию кода в зависимости от аргументов шаблона?

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

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

Пример класса (упрощенный - без конструктора и т.д.):

МойКласс.h

template<int Dimension, typename TPixelType = float>
    class MyClass
{
    void DoSomething();
    void DoAnotherThing(); // this function should only be available if Dimension > 2
}

MyClass.cxx

template< int Dimension, typename TPixelType> void MyClass::DoSomething()
{...}

// pseudocode: if Dimension <= 2 do not compile next function
template< int Dimension, typename TPixelType> void MyClass::DoAnotherThing() 
{
    MethodNotToBeCompiled(); // The function I don't want to be executed
}

TestMyClass.cxx

int main()
{
    auto myclass0 = MyClass<2>();
    myclass0.DoSomething(); // OK
    myclass0.DoAnotherThing(); // (wanted) error - function not available

    auto myclass1 = MyClass<3>();
    myclass1.DoSomething(); // OK
    myclass1.DoAnotherThing(); // OK
}

Возможно ли это в C++XX? Или есть другой подход, чем директивы препроцессора?

не вопрос, но актуально: stackoverflow.com/questions/495021/…

463035818_is_not_a_number 23.05.2019 11:04

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

463035818_is_not_a_number 23.05.2019 11:05

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

Max Langhof 23.05.2019 11:05
static_assert(2 < Dimension)
user7860670 23.05.2019 11:06
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
4
156
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

template <int Dimension, typename TPixelType> void MyClass::DoSomething()  {/*...*/}

// if Dimension <= 2 do not compile next function
template <int Dimension, typename TPixelType>
void MyClass::DoAnotherThing() 
{
    static_assert(Dimension > 2, "function not available!" );
    // ...
}

Как мне обрабатывать код после static_assert()? Кажется, что static_assert влияет на весь процесс компиляции. Я просто хочу, чтобы единственная функция не компилировалась.

KabCode 23.05.2019 11:37

что ты имеешь в виду? когда вы используете эту функцию с недопустимым параметром (<=2), компилятор не позволяет вам это сделать и выдает ошибку function not available!. Код после static_assert() должен быть как обычный код, разницы нет. В примере после static_assert(...); можно поставить: int i = Dimension * 3;

Raffallo 23.05.2019 11:44

Предотвращает ли утверждение компиляцию этого метода или только его выполнение? Я пытаюсь выяснить, в какой момент static_assert раскрывает свою функциональность.

KabCode 23.05.2019 13:36

@KabCode static_assert выдает ошибку времени компиляции, поэтому компиляция невозможна.

Raffallo 23.05.2019 13:52

В C++2a вы можете использовать requires для "отбрасывания" метода:

template<int Dimension, typename TPixelType = float>
class MyClass
{
    void DoSomething();
    void DoAnotherThing() requires (Dimension > 2);
};

Как далеко продвинулась реализация C++2a? Может ли он уже использоваться (с визуальным компилятором)?

KabCode 23.05.2019 11:10

Вы можете посмотреть на docs.microsoft.com/en-us/cpp/overview/…. Так что в настоящее время еще не поддерживается в Visual (gcc поддерживает requires).

Jarod42 23.05.2019 11:16

Это был бы мой предпочтительный ответ, если бы я мог использовать requires.

KabCode 23.05.2019 14:10

@Jarod42 слишком опередил свое время :-) тем не менее, классное решение, счастлив, что попробовал это!

andreee 23.05.2019 14:17
Ответ принят как подходящий

Общее предложение: если у вас есть класс шаблона, реализуйте все в заголовке и избегайте файлов cpp. Все стало намного проще.

can I prevent the generation of a function of a templated class if the template arguments does not meet a criteria (certain value or type)? Can this be achieved by using c++ code and no preprocessor directives?

Да и да: ищите SFINAE.

В вашем случае (С++ 11 и новее)

template <int Dimension, typename TPixelType = float>
class MyClass
 {
   public:
      void DoSomething ()
       { }

      template <int D = Dimension,
                typename std::enable_if<(D > 2), bool>::type = true>
      void DoAnotherThing()
       { }
 };

Теперь метод DoAnotherThing() реализуется только тогда, когда D > 2 где D по умолчанию равно Dimension.

Не идеальное решение, потому что его можно «угнать», объясняя значение D

auto myclass0 = MyClass<2>();
myclass0.DoAnotherThing<5>(); // compile because D is 5

но вы можете предотвратить эту проблему, добавив тест, что D равно Dimension

  template <int D = Dimension, // ..VVVVVVVVVVVVVVVV
            typename std::enable_if<(D == Dimension)
                                 && (D > 2), bool>::type = true>
  void DoAnotherThing()
   { }

так

auto myclass0 = MyClass<2>();
myclass0.DoAnotherThing<5>(); // doesn't compile anymore because 5 != 2

Это можно комбинировать с if constexpr(){}, чтобы предотвратить вызов функции, вызывающий ошибки времени компиляции.

KabCode 28.05.2019 09:12

Другие вопросы по теме