简体   繁体   中英

Overloading and template specialization for function call priority

With reference to the following code:

I am trying to conditionally compile a bunch of functions and then 'order' them using the prioirty_tag class . My question is, if I replace enable_if_t<is_nothrow_move_constructible<U>{}>* = nullptr> with enable_if_t<is_nothrow_move_constructible<U>{}>> the output is incorrect (defaults to the first function).

What exactly is happening there? why does adding the * = nullptr make it work?

#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;
}

Try to compile below code

template<void>
void foo(){}

I got compiler error 'void' is not a valid type for a template non-type parameter .


As template parameter you can pass:

1) type then you declare it using class/typename as below:

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

2) non-type then you can pass as template parameter some intergers value, pointers, Lvalue reference, etc (full list here )

template<void*>
void foo3(){}

3) template type parameter

In your example is_nothrow_move_constructible returns true for A , then compiler meets line:

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

what is:

template <typename U = T, void>

this line has incorrect syntax, and compiler removes this member function template from overloads set. You can fix it by declaring enable_if_t<is_nothrow_move_constructible<U>{} as type parameter:

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";
    };

or as non-type (pointer to void), what you did in your example.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM