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.