C ++ создает экземпляр класса, только если выполняется условие для типа шаблона - PullRequest
0 голосов
/ 03 июня 2018

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

Я работаю над классом, где тип шаблона должен иметь времясоставная часть.В идеале тип является производным от класса, который определяет время только как член.Таким образом, выполнение чего-то подобного должно быть безопасным:

#include <type_traits>
#include <stdexcept>

class Time
{
  public:
    double t;
};

class A : Time
{

};

template<class T>
class B
{
    T data;

    void do_someting()
    {
      data.t = 12.34;
    }
};

B<A> some_instance;

Я обнаружил шаблоны C ++, которые принимают только определенные типы

Так что следующая проверка будет выполнять, но static_assert проверяет только во время компиляции.

template<class T>
class B
{
    static_assert(std::is_base_of<Time, T>::value, "T must inherit from Time Class");
    T data;

    void do_someting()
    {
      data.t = 12.34;
    }
};

Было бы безопасно сделать следующее или есть более чистый способ архивирования этого?

Редактировать: Изменено из-за ввода Тимоса.

template<class T>
class B
{
  B()
  {
    if(std::is_base_of<Time, T>::value)
    {
      throw std::invalid_argument( "T must inherit from Time Class" );
    }
  }

    T data;

    void do_someting()
    {
      data.t = 12.34;
    }
};

Ответы [ 3 ]

0 голосов
/ 03 июня 2018

Идея хорошая, но реализация неправильная.Это должно выглядеть так:

templacte <T, Base>
class ThrowIfNotBaseOf {
    void checkIt() {
        if(!std::is_base_of<Base, T>::value) {
            throw std::invalid_argument( "T must inherit from Time Class" );
        }
    }

public:
    TypeCheckThrow() { // default constructor
        checkIt();
    }

    TypeCheckThrow(const TypeCheckThrow<T, Base> &) { // copy constructor
        checkIt();
    }

    TypeCheckThrow(TypeCheckThrow<T, Base> &&) { // move constructor
        checkIt();
    }
};

template<class T>
class B
{
    ThrowIfNotBaseOf<T, Time> typeCheckThrow;

    T data;

    void do_someting()
    {
      data.t = 12.34;
    }
};

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

0 голосов
/ 04 июня 2018

Используйте std :: enable_if, который предназначен именно для этой цели.Это приведет к ошибке времени компиляции, если условие не выполнено.

#include <type_traits>
#include <stdexcept>

class Time
{
  public:
    double t;
};

class A : Time
{

};

class C
{

};

template<class T, class _T=typename std::enable_if<std::is_base_of<Time, T>::value, T>::type >
class B 
{
    T data;

    void do_someting()
    {
      data.t = 12.34;
    }
};

B<A> some_instance;
//B<C> other_instance; // error
0 голосов
/ 03 июня 2018

Я немного запутался в том, что вы пытаетесь достичь.Насколько я понимаю, вы хотите предотвратить использование B с классами, которые не наследуются от Time.

. Для этого решение с static_assert является лучшим решением.Одной из сильных сторон C ++ является то, что вы можете вызвать ошибки компиляции, когда предусловие нарушается.В слабо типизированных языках, таких как Javascript, PHP, Bash ... это может вызвать ошибку во время выполнения, которая требует наличия тестового примера для этого куска кода.

Другое решение за исключением не добавляет никаких преимуществ, так как if-statement будет оцениваться во время компиляции и фактически будет if (true) или if (false).

Таким образом, написавВторое решение - вам действительно нужно больше времени для отладки кода, поскольку вы должны запустить свой исполняемый файл, запустить тестовый пример, который использует этот код, и проверить поведение с помощью отладчика.Все это можно предотвратить с помощью static_assert.

...