Как включить специализацию класса шаблона, если параметром шаблона является bidirectional_iterator? - PullRequest
1 голос
/ 09 апреля 2019

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

Я пытаюсь использовать для этого enable_if и iterator_category , но я не могу понять, что происходит не так. Я использую оба gcc 8.3.1 и clang 7 в Linux с -std = c ++ 17 . Я также пробовал другие компиляторы на Compiler Explorer .

(Примечание: я также пытался использовать is_same_v вместо is_base_of_v , но с тем же результатом или отсутствием ...)

#include <iterator>
#include <type_traits>
#include <vector>

template<typename It>
using it_cat = typename std::iterator_traits<It>::iterator_category;

template<typename BidIt,
        typename std::enable_if_t<std::is_base_of_v<it_cat<BidIt>, std::bidirectional_iterator_tag>> = 0
        >
class A {
    BidIt start;
public:        
//  A() : start {} {}
    A(BidIt s_) : start {s_} {}
};


// A<std::vector<int>::iterator> a1;


int main()
{
    std::vector<int> v {0, 1, 2, 3};
    A a2 {v.begin()};
}

Две закомментированные строки были попыткой вручную создать пустой объект типа A путем явной передачи параметра (без успеха). Выходные данные компилятора ясно показывают, что вывод типа не выполняется:

error: no type named 'type' in 'struct std::enable_if<false, void>'

typename std::enable_if_t<std::is_base_of_v<it_cat<BidIt>, std::bidirectional_iterator_tag>> = 0

и, насколько я понимаю, enable_if оценивается как false.

1 Ответ

0 голосов
/ 09 апреля 2019

Во-первых, вы используете черту назад. std::is_base_of<Base, Derived> проверяет, является ли первое основанием второго. Таким образом, ваш чек должен быть is_base_of_v<bidirectional_iterator_tag, it_cat<BidIt>>.

Во-вторых, идиома C ++ 17 для выполнения этого вида условного включения (при условии, что вы хотите иметь другие специализации) должна иметь по умолчанию второй параметр шаблона:

template <typename T, typename Enable = void>
struct X; // the primary

template <typename T>
struct X<T, std::enable_if_t</* condition */>> // the conditional specialization
{ ... };

Если вам не нужна другая специализация, мы можем сделать это более простым способом:

template <typename T>
struct X {
    static_assert(/* the condition */, "!");
};
...