Перегрузка и специализация шаблона для приоритета вызова функции - PullRequest
0 голосов
/ 03 марта 2019

Со ссылкой на следующий код:

Я пытаюсь условно скомпилировать несколько функций и затем «упорядочить» их, используя prioirty_tag class.Мой вопрос: если я заменим enable_if_t<is_nothrow_move_constructible<U>{}>* = nullptr> на enable_if_t<is_nothrow_move_constructible<U>{}>>, то вывод будет неправильным (по умолчанию первая функция).

Что именно там происходит?почему добавление * = nullptr заставляет его работать?

#include <iostream>
#include <type_traits>

using namespace std;

template <size_t T>
struct priority_tag: priority_tag<T-1> {};
template <>
struct priority_tag<0> {};

template <typename T>
struct my_vec
{   
        template <typename U = T, typename = void>
        void realloc_impl(priority_tag<0> pr)
        {
            cout << "Move throw construct\n";
        };

        //template <typename U = T, enable_if_t<is_copy_constructible<U>{}>> this wont work!

        template <typename U = T, enable_if_t<is_copy_constructible<U>{}>* = nullptr>
        void realloc_impl(priority_tag<1> pr)
        {
            cout << "copy construct \n";
        };

        //template <typename U = T, enable_if_t<is_copy_constructible<U>{}>> this wont work!

        template <typename U = T, enable_if_t<is_nothrow_move_constructible<U>{}>* = nullptr>
            void realloc_impl(priority_tag<2> pr)
        {
            cout << "nothrow move \n";
        };
        void realloc()
        {
                priority_tag<2> pr;
                realloc_impl(pr);
        }

        const static int val = is_nothrow_move_constructible<T>{} ? 1 : is_copy_constructible<T>{} ? 2 : 3;

        priority_tag<val> g;

};

class A {
public:
    A() = default;
    A(A&&) noexcept = default;
};

class B {
public:
    B() = default;
    B(B&&) = delete;
    B(const B&) = default;
};

class C {
public:
    C() = default;
    C(C&&) {}
    C(const C&) = delete;
};


int main()
{
        my_vec<A> obj;
        obj.realloc();

        cout << obj.val;
}

1 Ответ

0 голосов
/ 03 марта 2019

Попробуйте скомпилировать ниже код

template<void>
void foo(){}

Я получил ошибку компилятора 'void' недопустимый тип для параметра не тип шаблона .


В качестве параметра шаблона вы можете передать:

1) type , затем вы объявляете его, используя class / typename, как показано ниже:

template< class/typename A[optional] = void>
void foo2(){}

2) non-type тогда вы можете передать в качестве параметра шаблона некоторое значение типа integer, указатели, ссылку на Lvalue и т. д. (полный список здесь )

template<void*>
void foo3(){}

3) параметр типа шаблона

В вашем примере is_nothrow_move_constructible возвращает true для A, тогда компилятор встречает строку:

template <typename U = T, enable_if_t<is_nothrow_move_constructible<U>{}>>

что такое:

template <typename U = T, void>

эта строка имеет неверный синтаксис, и компиляторудаляет этот шаблон функции-члена из набора перегрузок.Вы можете исправить это, объявив enable_if_t<is_nothrow_move_constructible<U>{} в качестве параметра типа:

template <typename U = T, 
          typename   = enable_if_t<is_nothrow_move_constructible<U>{}> > // typename = void
    void realloc_impl(priority_tag<2> pr)
    {
        cout << "nothrow move \n";
    };

или в качестве нетипового (указатель на void), что вы сделали в своем примере.

...