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.
Related
I want to store multiple non-movable types in a single variable.
At the very first, I have tried std::tuple at the very first, but it fails.
#include <tuple>
template<typename T>
struct No {
No(T){}
No(const No &) = delete;
No(No &&) = delete;
};
struct Handmade {
No<int> a;
No<double> b;
No<char> c;
};
template<typename T>
auto no() -> No<T> { return No<T>(T()); }
auto main() -> int
{
Handmade h = {no<int>(), no<double>(), no<char>()}; // good
auto tuple = std::make_tuple(no<int>(), no<double>(), no<char>()); // fails
return 0;
}
Here, Handmade type can be initialized through aggregate initialization.
However, std::tuple is not aggregate-initialzable, it doesn't work.
Since it should be variadic, I cannot write such type Handmade for my purpose.
Is it possible to implement such variadic tepmlate data structure in current C++ standard or is there any workaround?
Yes, you can write your own aggregate tuple like this:
template <int I, typename T>
struct MyTupleElem
{
T value{};
template <int J> requires(I == J) T &get() {return value;}
template <int J> requires(I == J) const T &get() const {return value;}
};
template <typename T, typename ...P>
struct MyTupleHelper;
template <int ...I, typename ...P>
struct MyTupleHelper<std::integer_sequence<int, I...>, P...>
: MyTupleElem<I, P>...
{
using MyTupleElem<I, P>::get...;
};
template <typename ...P>
struct MyTuple : MyTupleHelper<std::make_integer_sequence<int, sizeof...(P)>, P...> {};
template <typename ...P>
MyTuple(P &&...) -> MyTuple<std::decay_t<P>...>;
template <typename T>
struct No
{
T value;
No(T value) : value(value) {}
No(const No &) = delete;
No(No &&) = delete;
};
template <typename T>
No<T> no(T t) {return No<T>(t);}
int main()
{
MyTuple h = {no<int>(1), no<double>(2.3), no<char>('4')};
std::cout << h.get<0>().value << '\n';
std::cout << h.get<1>().value << '\n';
std::cout << h.get<2>().value << '\n';
}
And I think it's a good way to make tuples in general, even if you don't want aggregate-ness. Last time I tested, such tuples could tolerate more elements than the classic ones with the bases chained on top of each other.
I want my class use another implementation for types don't have constexpr constructor.
like this:
template <typename A>
class foo
{
public:
// if A has constexpr constructor
constexpr foo() :_flag(true) { _data._a = A(); }
// else
constexpr foo() : _flag(false) { _data.x = 0; }
~foo(){}
bool _flag;
union _data_t
{
_data_t() {} // nothing, because it's just an example
~_data_t() {}
A _a;
int x;
}_data;
};
To achieve what the title says, I try this:
template<typename _t, _t = _t()>
constexpr bool f()
{
return true;
}
template<typename _t>
constexpr bool f()
{
return false;
}
It works well for types haven't constexpr constructor.
But for other types it causes a compile error with ambiguous overloads.
so how can I check?
I suppose you can use SFINAE together with the power of the comma operator
Following your idea, you can rewrite your f() functions as follows
template <typename T, int = (T{}, 0)>
constexpr bool f (int)
{ return true; }
template <typename>
constexpr bool f (long)
{ return false; }
Observe the trick: int = (T{}, 0) for the second template argument
This way f() is enabled (power of the comma operator) only if T{} can be constexpr constructed (because (T{}, 0) is the argument for a template parameter), otherwise SFINAE wipe away the first version of f().
And observe that the fist version of f() receive an unused int where the second one receive a long. This way the first version is preferred, when available, calling f() with an int; the second one is selected, as better than nothing solution, when the first one is unavailable (when the first template argument isn't constexpr default constructible).
Now you can construct two template constructors for foo that you can alternatively enable/disable according the fact the template parameter T (defaulted to A) is or isn't constexpr constructible
template <typename T = A,
std::enable_if_t<f<T>(0), std::nullptr_t> = nullptr>
constexpr foo() { std::cout << "constexpr" << std::endl; }
template <typename T = A,
std::enable_if_t<not f<T>(0), std::nullptr_t> = nullptr>
constexpr foo() { std::cout << "not constexpr" << std::endl; }
The following is a full compiling example (C++14 or newer, but you can modify it for C++11):
#include <iostream>
#include <type_traits>
template <typename T, int = (T{}, 0)>
constexpr bool f (int)
{ return true; }
template <typename>
constexpr bool f (long)
{ return false; }
template <typename A>
struct foo
{
template <typename T = A,
std::enable_if_t<f<T>(0), std::nullptr_t> = nullptr>
constexpr foo() { std::cout << "constexpr" << std::endl; }
template <typename T = A,
std::enable_if_t<not f<T>(0), std::nullptr_t> = nullptr>
constexpr foo() { std::cout << "not constexpr" << std::endl; }
};
struct X1 { constexpr X1 () {} };
struct X2 { X2 () {} };
int main()
{
foo<X1> f1; // print "constexpr"
foo<X2> f2; // print "not constexpr"
}
This is a follow-up to my previous question.
I have a class with a cast operator to anything. In a pre-C++17 environment this yields errors of being unable to select appropriate constructor overload while performing initialization. I want to tune the behavior by marking the cast operator explicit for some types. However, I cannot find a way to do so.
Here is an artificial example: I want an implicit cast operator to integer types and explicit to all other types.
This doesn't work because we cannot determine U having the expression of type typename std::enable_if<!std::is_integral<U>::value, U>::type:
struct C {
template<typename U>
operator typename std::enable_if< std::is_integral<U>::value, U>::type() const {
return 1;
}
template<typename U>
explicit operator typename std::enable_if<!std::is_integral<U>::value, U>::type() const {
return 1.5;
}
};
This one fails to compile saying that C::operator U() cannot be overloaded:
struct C {
template<typename U, typename = typename std::enable_if< std::is_integral<U>::value, U>::type>
operator U() const {
return 1;
}
template<typename U, typename = typename std::enable_if<!std::is_integral<U>::value, U>::type>
explicit operator U() const {
return 1.5;
}
};
I cannot declare the function of kind template<typename U, typename = void> operator U(); and partially specialize it because partial function specialization is not allowed and making a helper class looks like an overkill to me.
How can I declare cast operator based on some traits of the type I'm casting to?
I need a C++11 solution, as in C++17 the issue from my previous question is already resolved.b
You can move definitions of these operators to the base classes. This approach allows you put constraints on both implicit and explicit operators:
#include <type_traits>
#include <iostream>
template<typename TDerived> class
t_ImplicitlyConvertableToAnything
{
public: template
<
typename TTarget
, typename TEnabled = typename ::std::enable_if_t<::std::is_integral<TTarget>::value>
>
operator TTarget(void) const
{
auto const & self{static_cast<const TDerived &>(*this)};
return(self.template CheckedConversion_To_Integral<TTarget>());
}
};
template<typename TDerived> class
t_ExplicitlyConvertableToAnything
{
public: template
<
typename TTarget
, typename TEnabled = typename ::std::enable_if_t<!::std::is_integral<TTarget>::value>
> explicit
operator TTarget(void) const
{
auto const & self{static_cast<const TDerived &>(*this)};
return(self.template CheckedConversion_To_NonIntegral<TTarget>());
}
};
class
t_ConvertableToAnything
: public t_ImplicitlyConvertableToAnything<t_ConvertableToAnything>
, public t_ExplicitlyConvertableToAnything<t_ConvertableToAnything>
{
public: template<typename TTarget> decltype(auto)
CheckedConversion_To_Integral(void) const
{
return(static_cast<TTarget>(1));
}
public: template<typename TTarget> decltype(auto)
CheckedConversion_To_NonIntegral(void) const
{
return(static_cast<TTarget>(3.14));
}
};
int main()
{
t_ConvertableToAnything c;
::std::cout << ([](int x){return(x);})(c) << ::std::endl;
::std::cout << static_cast<float>(c) << ::std::endl;
return(0);
}
Run this code online
You can use non-type template parameters to avoid the "cannot be overloaded" issue:
#include <iostream>
#include <type_traits>
struct A { };
struct B { };
struct C {
template <typename U,
typename std::enable_if<std::is_integral<U>::value>::type* = nullptr>
explicit operator U() const {
return 1;
}
template<typename U,
typename std::enable_if<std::is_same<U, A>::value>::type* = nullptr>
explicit operator U() const {
return A{ };
}
template<typename U,
typename std::enable_if<std::is_same<U, B>::value>::type* = nullptr>
explicit operator U() const {
return B{ };
}
};
int main() {
C c;
long y = static_cast<int>(c);
B b = static_cast<B>(c);
A a = static_cast<A>(c);
}
https://ideone.com/smfPwF
You can overload your cast operator using a trick with dummy template parameters for disambiguation.
struct C {
template<typename U,
typename = typename enable_if<is_integral<U>::value, U>::type,
int = 0> // <== hete
operator U() const {
return 1;
}
template<typename U,
typename = typename enable_if<!is_integral<U>::value, U>::type,
char = 0> // <== and here
explicit operator U() const {
return 1.5;
}
};
Since the template signatures are now different, there is no ambiguity.
Try this. Just leave off the constraints on the explicit operator since it covers all cases that the first operator does not.
Coliru example: http://coliru.stacked-crooked.com/a/3d0bc6e59ece55cf
#include <iostream>
#include <type_traits>
struct C {
template <typename U,
typename = typename std::enable_if< std::is_integral<U>::value>::type>
operator U() const {
return 1;
}
template<typename U, typename std::enable_if<!std::is_integral<U>::value>::type* = nullptr>
explicit operator U() const {
return 1.5;
}
};
int main() {
C c;
int v = c;
int w = c;
int x = static_cast<int>(c);
long y = static_cast<int>(c);
double z = static_cast<double>(c);
std::cout << v << std::endl;
std::cout << w << std::endl;
std::cout << x << std::endl;
std::cout << y << std::endl;
std::cout << z << std::endl;
}
Thanks to #Jodocus for enabling explicit casts to integral types.
Is the following program compliant C++11? If so, do you know of a specific MSVC bug that triggers it? and/or a possible work-around?
#include <iostream>
struct A {};
struct B {};
constexpr A aaa = {};
constexpr B bbb = {};
template <typename T>
void foo(T, decltype(aaa)) { std::cout << "a"; }
template <typename T>
void foo(T, decltype(bbb)) { std::cout << "b"; }
// ^ C2995 'void foo(T,unknown-type)': function template has already been defined
int main()
{
foo(0, aaa);
foo(0, bbb);
}
If the actual types are substituted for decltype then it works, but in practice these types are too complicated to reproduce and I'd prefer not to have aliases for them.
Works for me (VS 2015 / v140) with the following minor modification:
#include <iostream>
struct A {};
struct B {};
constexpr A aaa = {};
constexpr B bbb = {};
using A_type = decltype(aaa);
using B_type = decltype(bbb);
template <typename T>
void foo(T, A_type) { std::cout << "a"; }
template <typename T>
void foo(T, B_type) { std::cout << "b"; }
int main()
{
foo(0, aaa);
foo(0, bbb);
}
But this variant yields the same error (not sure what to make of it):
template <typename T>
struct TypeWrapper {
using type = T;
};
template <typename T>
void foo(T, typename TypeWrapper<decltype(aaa)>::type) { std::cout << "a"; }
template <typename T>
void foo(T, typename TypeWrapper<decltype(bbb)>::type) { std::cout << "b"; }
I need to create a template function like this:
template<typename T>
void foo(T a)
{
if (T is a subclass of class Bar)
do this
else
do something else
}
I can also imagine doing it using template specialization ... but I have never seen a template specialization for all subclasses of a superclass. I don't want to repeat specialization code for each subclass
You can do what you want but not how you are trying to do it! You can use std::enable_if together with std::is_base_of:
#include <iostream>
#include <utility>
#include <type_traits>
struct Bar { virtual ~Bar() {} };
struct Foo: Bar {};
struct Faz {};
template <typename T>
typename std::enable_if<std::is_base_of<Bar, T>::value>::type
foo(char const* type, T) {
std::cout << type << " is derived from Bar\n";
}
template <typename T>
typename std::enable_if<!std::is_base_of<Bar, T>::value>::type
foo(char const* type, T) {
std::cout << type << " is NOT derived from Bar\n";
}
int main()
{
foo("Foo", Foo());
foo("Faz", Faz());
}
Since this stuff gets more wide-spread, people have discussed having some sort of static if but so far it hasn't come into existance.
Both std::enable_if and std::is_base_of (declared in <type_traits>) are new in C++2011. If you need to compile with a C++2003 compiler you can either use their implementation from Boost (you need to change the namespace to boost and include "boost/utility.hpp" and "boost/enable_if.hpp" instead of the respective standard headers). Alternatively, if you can't use Boost, both of these class template can be implemented quite easily.
I would use std::is_base_of along with local class as :
#include <type_traits> //you must include this: C++11 solution!
template<typename T>
void foo(T a)
{
struct local
{
static void do_work(T & a, std::true_type const &)
{
//T is derived from Bar
}
static void do_work(T & a, std::false_type const &)
{
//T is not derived from Bar
}
};
local::do_work(a, std::is_base_of<Bar,T>());
}
Please note that std::is_base_of derives from std::integral_constant, so an object of former type can implicitly be converted into an object of latter type, which means std::is_base_of<Bar,T>() will convert into std::true_type or std::false_type depending upon the value of T. Also note that std::true_type and std::false_type are nothing but just typedefs, defined as:
typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;
I know this question has been answered but nobody mentioned that std::enable_if can be used as a second template parameter like this:
#include <type_traits>
class A {};
class B: public A {};
template<class T, typename std::enable_if<std::is_base_of<A, T>::value, int>::type = 0>
int foo(T t)
{
return 1;
}
I like this clear style:
void foo_detail(T a, const std::true_type&)
{
//do sub-class thing
}
void foo_detail(T a, const std::false_type&)
{
//do else
}
void foo(T a)
{
foo_detail(a, std::is_base_of<Bar, T>::value);
}
The problem is that indeed you cannot do something like this in C++17:
template<T>
struct convert_t {
static auto convert(T t) { /* err: no specialization */ }
}
template<T>
struct convert_t<T> {
// T should be subject to the constraint that it's a subclass of X
}
There are, however, two options to have the compiler select the correct method based on the class hierarchy involving tag dispatching and SFINAE.
Let's start with tag dispatching. The key here is that tag chosen is a pointer type. If B inherits from A, an overload with A* is selected for a value of type B*:
#include <iostream>
#include <type_traits>
struct type_to_convert {
type_to_convert(int i) : i(i) {};
type_to_convert(const type_to_convert&) = delete;
type_to_convert(type_to_convert&&) = delete;
int i;
};
struct X {
X(int i) : i(i) {};
X(const X &) = delete;
X(X &&) = delete;
public:
int i;
};
struct Y : X {
Y(int i) : X{i + 1} {}
};
struct A {};
template<typename>
static auto convert(const type_to_convert &t, int *) {
return t.i;
}
template<typename U>
static auto convert(const type_to_convert &t, X *) {
return U{t.i}; // will instantiate either X or a subtype
}
template<typename>
static auto convert(const type_to_convert &t, A *) {
return 42;
}
template<typename T /* requested type, though not necessarily gotten */>
static auto convert(const type_to_convert &t) {
return convert<T>(t, static_cast<T*>(nullptr));
}
int main() {
std::cout << convert<int>(type_to_convert{5}) << std::endl;
std::cout << convert<X>(type_to_convert{6}).i << std::endl;
std::cout << convert<Y>(type_to_convert{6}).i << std::endl;
std::cout << convert<A>(type_to_convert{-1}) << std::endl;
return 0;
}
Another option is to use SFINAE with enable_if. The key here is that while the snippet in the beginning of the question is invalid, this specialization isn't:
template<T, typename = void>
struct convert_t {
static auto convert(T t) { /* err: no specialization */ }
}
template<T>
struct convert_t<T, void> {
}
So our specializations can keep a fully generic first parameter as long we make sure only one of them is valid at any given point. For this, we need to fashion mutually exclusive conditions. Example:
template<typename T /* requested type, though not necessarily gotten */,
typename = void>
struct convert_t {
static auto convert(const type_to_convert &t) {
static_assert(!sizeof(T), "no conversion");
}
};
template<>
struct convert_t<int> {
static auto convert(const type_to_convert &t) {
return t.i;
}
};
template<typename T>
struct convert_t<T, std::enable_if_t<std::is_base_of_v<X, T>>> {
static auto convert(const type_to_convert &t) {
return T{t.i}; // will instantiate either X or a subtype
}
};
template<typename T>
struct convert_t<T, std::enable_if_t<std::is_base_of_v<A, T>>> {
static auto convert(const type_to_convert &t) {
return 42; // will instantiate either X or a subtype
}
};
template<typename T>
auto convert(const type_to_convert& t) {
return convert_t<T>::convert(t);
}
Note: the specific example in the text of the question can be solved with constexpr, though:
template<typename T>
void foo(T a) {
if constexpr(std::is_base_of_v<Bar, T>)
// do this
else
// do something else
}
If you are allowed to use C++20 concepts, all this becomes almost trivial:
template<typename T> concept IsChildOfX = std::is_base_of<X, T>::value;
// then...
template<IsChildOfX X>
void somefunc( X& x ) {...}