LINUX.ORG.RU

Ограничение на типы параметров шаблонов в C++

 , проверка типов,


0

3

В Scala я могу задать проверку на тип параметра дженерика так

class Foo [T <: A] //Тип Т является расширением типа A

//или 
class Bar [T % A] //Тип T имеет неявное преобразование к типу А

А как такие веще мне смоделировать в C++ (стандарт вплоть до С++17)?

Кто-то сталкивался с таким?

Зависит от того, что вам нужно. Можно применять static_assert для того, чтобы нельзя было подсунуть тип, не удовлетворяющий вашим условиям. Что-то вроде:

template<typename T>
class my_type {
  static_assert(std::is_base_of_v<A, T>);
  ...
};

Можно применять SFINAE для того, чтобы выбирать реализацию в зависимости от того, определены ли какие-то операции или нет.

Можно и обычной специализацией шаблонов пользоваться.

eao197 ★★★★★
()

class Foo [T <: A] //Тип Т является расширением типа A

// с++17
#include <type_traits>

class A {};
class B : public A {};

class C {};

template<typename T,
    typename = std::enable_if_t<
        std::is_base_of_v<A, T>
    >
>
class Foo {};

int main() {
    
    Foo<A> a; // Ок
    Foo<B> b; // Ок
    Foo<C> c; // error: no type named 'type' in 'struct std::enable_if<false, void>'

    return 0;
}

Про неявное приведение надо подумать.

ox55ff ★★★★★
()
Последнее исправление: ox55ff (всего исправлений: 2)

class Bar [T % A] //Тип T имеет неявное преобразование к типу А

Про именно неявное не знаю. Сделано на основе проверки возможности приведения указателя на T к указателю на тип A. Не уверен, что эта схема корректна. Я так у себя в коде не делал.

// c++17
#include <type_traits>

class A {};
class B : public A {};

class C {};

template<typename T,
    typename = std::enable_if_t<
        std::is_convertible_v<std::decay_t<T>*, std::decay_t<A>*>
    >
>
class Foo {};

int main() {
   
    Foo<A> a; // Ok
    Foo<B> b; // Ok
    Foo<C> c; // error: no type named 'type' in 'struct std::enable_if<false, void>'

    return 0;
}
ox55ff ★★★★★
()
Ответ на: комментарий от AntonI

Концепты в C++20. Именно контракты, о которых речь шла при работе над C++20, в стандарт пока не попали (емнип, даже в C++23).

Но ТС-у нужно было до C++17 включительно.

Причем я так и не понял что именно: способ задания ограничений на типы параметров шаблона или способ выяснения взаимоотношение между типами (как то: производен от, имеются ли преобразования, …)

eao197 ★★★★★
()
Ответ на: комментарий от eao197

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

LongLiveUbuntu ★★★★★
() автор топика
Ответ на: комментарий от LongLiveUbuntu

Если у вас типы наследуются от общей базы, то может и шаблон не нужен? Достаточно ведь просто сделать метод/функцию, принимающую ссылку на базовый тип.

Если же типы у вас не связаны наследованием и таки нужен шаблон, то на мой взгляд, в C++ до 17-го стандарта включительно, проще всего использовать static_assert внутри самого шаблона. Да еще и с текстовой строкой пояснением что именно ожидается. В сообщениях об ошибках тогда проще разобраться, чем в случае, когда компилятор не находит нужную перегрузку и начинает перечислять что он попробовал, но не смог выбрать.

eao197 ★★★★★
()
4 июля 2023 г.