boost::enable_if with two conditions - c++

As you can see in the following example, I currently use a boost::enable_if as return value of an allocation function. The goal is to avoid a compilation error for abstract types:
template <typename T>
typename boost::enable_if<boost::is_abstract<T>,T*>::type no_abstract_new()
{
assert(false);
return 0;
}
template <typename T>
typename boost::disable_if<boost::is_abstract<T>,T*>::type no_abstract_new()
{
return new T;
}
Now, I also want to exclude classes inheriting from a own class named has_no_default_constructor. Is there a way to have a or in the condition of boost::enable_if ? Somthing like this uncorrect code:
template <typename T>
typename boost::enable_if<boost::is_abstract<T>
|| boost::is_base_of<has_no_default_constructor,T>,T*>::type default_constructor_new()
{
assert(false);
return 0;
}
template <typename T>
typename boost::disable_if<boost::is_abstract<T>
|| boost::is_base_of<has_no_default_constructor,T>,T*>::type default_constructor_new()
{
return new T;
}
Or have I to implement a own class of trait doing the job ? (I'm totally lost for this. I understand the idea, but I feel enable to do it myself)
Notes:
I don't use C++11 for compatibility reason
I know has_default_constructor exists in C++11, but not before C++11
boost::has_default_constructor exists but is only an alias of boost::has_trivial_constructor if compiled without C++11

There is also
template <bool B, class T = void> struct enable_if_c;
note that it takes a bool as first parameter not a type. Hence the following should be fine
template <typename T>
typename boost::enable_if_c<boost::is_abstract<T>::value
|| boost::is_base_of<has_no_default_constructor,T>::value
,T*>::type default_constructor_new()
{
assert(false);
return 0;
}
and similar for the other overload.

Related

C++20 requires expression does not catch static_assert

I was really excited when I first heard about C++20 constraints and concepts, and so far I've been having a lot of fun testing them out. Recently, I wanted to see if it's possible to use C++20 concepts to test the constraints of classes or functions. For example:
template <int N>
requires (N > 0)
class MyArray { ... };
template <int N>
concept my_array_compiles = requires {
typename MyArray<N>;
};
my_array_compiles<1>; // true
my_array_compiles<0>; // false
At first I didn't have any issues, but I encountered a case where static_assert in a dependent function prevents compilation, even though it appears in a requires expression. Here is an example that illustrates this:
template <bool b>
requires b
struct TestA {
void foo() {}
};
template <bool b>
struct TestB {
static_assert(b);
void foo() {}
};
template <template<bool> class T, bool b>
concept can_foo = requires (T<b> test) {
test.foo();
};
can_foo<TestA, true>; // true
can_foo<TestA, false>; // false
can_foo<TestB, true>; // true
// can_foo<TestB, false>; does not compile
TestA and TestB should work similarly for most use cases (although I found that TestB<false> can be used as a type as long as it isn't instantiated or dereferenced). However, my expectation was that a failed static_assert within a requires expression would cause it to evaluate to false instead. This is especially important for using library code that still uses static_assert. For example, std::tuple_element:
template <class T>
concept has_element_0 = requires {
typename tuple_element_t<0, T>;
};
has_element_0<tuple<int>>; // true
// has_element_0<tuple<>>; does not compile
When I pass in an empty tuple to the above concept, I get the error static_assert failed due to requirement '0UL < sizeof...(_Types)' "tuple_element index out of range". I've tested this on g++ 10.3.0 and clang 12.0.5. I was able to work around this issue by providing a wrapper that uses constraints, but it somewhat defeats the purpose since I am essentially preventing the compiler from seeing the static_assert by enforcing the same condition at a higher level.
template <size_t I, class T>
requires (I >= 0) && (I < tuple_size_v<T>)
using Type = tuple_element_t<I, T>;
template <class T>
concept has_element_0 = requires {
typename Type<0, T>;
};
has_element_0<tuple<int>>; // true
has_element_0<tuple<>>; // false
And it doesn't always work depending on how std::tuple_element is used:
template <size_t I, class T>
requires (I >= 0) && (I < tuple_size_v<T>)
tuple_element_t<I, T> myGet(const T& tup) {
return get<I>(tup);
}
template <class T>
concept has_element_0 = requires (T tup) {
myGet<0>(tup);
};
has_element_0<tuple<int>>; // true
// has_element_0<tuple<>>; does not compile
So ultimately my questions are: is this expected behavior that requires expressions don't take static_assert into account? If so, what was the reason for that design? And finally, is there a better way to accomplish my goal on classes with static_assert without using the above workaround?
Thanks for reading.
Yes, nothing in the content of the stuff you interact with is checked. Just the immediate context of the declaration.
In some cases with decltype the non immediate context of some constructs is checked, but any errors remain hard.
This was done (way back) to reduce the requirements on compilers. Only in what is known as "immediate context" do the compilers need to be able to cleanly back out when they see an error and continue compiling.
Static assert is never suitable for this purpose. Static assert, if hit, ends the compilation.
If you want to avoid the static assert (that is expected to end compilation) then you need to provide an alternative.
Once the concept is designed, create a variant for the not (!) of that concept:
#include <tuple>
#include <variant>
template <std::size_t I, class T>
requires (I >= 0) && (I < std::tuple_size_v<T>)
using Type = std::tuple_element_t<I, T>;
template <class T>
concept has_element_0 = requires {
typename Type<0, T>;
};
bool test1()
{
return has_element_0<std::tuple<int>>; // true
}
bool test2()
{
return has_element_0<std::tuple<>>; // false
}
template <std::size_t I, class T>
requires (I >= 0) && (I < std::tuple_size_v<T>)
std::tuple_element_t<I, T> myGet_impl(const T& tup) {
return get<I>(tup);
}
template <class T>
concept alt_has_element_0 = requires (T tup) {
myGet_impl<0>(tup);
};
template <class T>
auto myGet0();
template <class T>
requires (alt_has_element_0<T>)
auto myGet0(const T& tup)
{
return myGet_impl<0, T>(tup);
}
auto test3()
{
std::tuple<int> X{7};
return myGet0(X); // true
}
template <class T>
requires (!alt_has_element_0<T>)
auto myGet0(const T& tup)
{
return std::monostate{};
}
auto test4()
{
std::tuple<> X;
return myGet0(X); // true
}
see it here;
Notice for test4() to compile, the code above defiles what to do if we do not fulfill the requirements of the concept. I stole std::monostate from variant for this.

C++17 how to test class has a member variable? [duplicate]

This question already has answers here:
How to detect whether there is a specific member variable in class?
(10 answers)
Closed 2 years ago.
I am going down the route
struct S {
static constexpr int extra=5;
};
struct V {
};
template <typename T>
void f()
{
if (std::is_same_v<decltype(T::extra), int>)
std::cout<< "extra exists" <<std::endl;
}
but calling f<S>() fails as
std::is_same_v<decltype(S::extra), int> == 0
and f<V>() does not compile
If you are stuck in c++17, there is some infrastructure that you can add to make detection like this much easier.
Detection-idiom
The most reusable/consistent way to detect features like this is via the Detection idiom, which leverages SFINAE through std::void_t in a template.
This can be taken verbatim from std::experimental::is_detected's page from cppreference. This effectively offers C++17 the ability to detect features in a way that is similiar to C++20's concepts; and the infrastructure can be reused easily for just about any detection.
The basics of what you would need are:
#include <type_traits>
namespace detail {
template <class Default, class AlwaysVoid,
template<class...> class Op, class... Args>
struct detector {
using value_t = std::false_type;
using type = Default;
};
template <class Default, template<class...> class Op, class... Args>
struct detector<Default, std::void_t<Op<Args...>>, Op, Args...> {
using value_t = std::true_type;
using type = Op<Args...>;
};
} // namespace detail
struct nonesuch{};
template <template<class...> class Op, class... Args>
using is_detected = typename detail::detector<nonesuch, void, Op, Args...>::value_t;
Note: The above infrastructure can be reused for any detection. It is a very useful reusable tool in C++17.
With is_detected, all you need is a detector, which is simply a template alias that evaluates to a decltype expression of something that may, or may not, exist.
So in your case, to conditionally detect the presence of T::extra, you can do this with a simple detector like:
template <typename T>
using detect_extra = decltype(T::extra);
Putting it all together now, you can use this detector to conditionally toggle the branch:
if constexpr (is_detected<detect_extra,T>::value) {
// Only do code if 'T' has 'T::extra' (e.g. 'S')
} else {
// Only do code if 'T' does not have 'T::extra' (e.g. 'V')
}
Live Example
If equivalent conversion to a specific type is important, such as extra needing to be convertible to int, you can also use is_detected_convertible and use the detector to check for if the result can be convertible to the desired type. Using the same cppreference page again, you can define is_detected_convertible as:
template <template<class...> class Op, class... Args>
using detected_t = typename detail::detector<nonesuch, void, Op, Args...>::type;
template <class To, template<class...> class Op, class... Args>
using is_detected_convertible = std::is_convertible<detected_t<Op, Args...>, To>;
Which allows the check to instead be:
if constexpr (is_detected_convertible<int, detect_extra, T>::value) {
// Only do code if 'T' has 'T::extra' convertible to int (e.g. 'S')
} else {
// Only do code if 'T' does not have 'T::extra', or is not int
}
Live Example
Concepts (C++20+ only)
If you have access to c++20 and beyond, concepts make this much simpler -- since you can simply use a concept + requires clause like:
#include <concepts> // std::same_as
template <typename T>
concept HasExtra = requires(T) {
{T::extra} -> std::same_as<int>;
};
if constexpr (HasExtra<T>) {
// Only do code if 'T' has 'T::extra' and is 'int' (e.g. 'S')
} else {
// Only do code if 'T' does not have 'T::extra' (e.g. 'V')
}
Live Example
Observe that decltype(T::extra) (when T is S) is int const (is constexpr so is also const), not int. This explain why f<S>() fails.
To test if a class has a member variable there are many ways, I suppose.
A possible solution is develop something as
void type_extra (...);
template <typename T>
auto type_extra (T t) -> decltype(t.extra);
template <typename T>
using type_extra_t = decltype(type_extra(std::declval<T>()));
Now you can write f() as follows
template <typename T>
void f()
{
if ( not std::is_same_v<type_extra_t<T>, void> )
{
std::cout<< "extra exists" <<std::endl;
if ( std::is_same_v<type_extra_t<T>, int> )
std::cout<< "(and is int)" << std::endl;
}
}
Observe that now the type_extra_t<S> is int, not int const; this way (getting the type from the returned type of a function) loose the constness of the variable.
If you want maintain the constness, you can return a reference from the function (so it return a int const & in the S case)
template <typename T>
auto type_extra (T t) -> decltype(t.extra) &;
and remove the reference from the using (so, in the S case, int const & become int const)
template <typename T>
using type_extra_t
= std::remove_reference_t<decltype(type_extra(std::declval<T>()))>;

C++ template functions with the same name but different return type

I am trying to make some file streamer that can read or write different types. Everything works except for the reading part with specific method. That method returns std::unique_ptr<T> when called and is a "wrapper" for another method that returns T. For some reason compiler does not use this method instead it tries to compile it with the other method (the one that returns T). The compilation fails because of this. I've already tried to search around internet but I can not find any accurate answer. Could you please help me with this.
The two methods I have defined:
template <typename T>
T read()
{
T obj;
obj.readFromFile<T>();
return std::move(obj);
}
and
template <
typename T,
template<typename> class D,
template<typename, typename> class Container
>
typename std::enable_if_t<
std::is_same<Container<T, D<T>>, std::unique_ptr<T, D<T>>>::value,
Container<T, D<T>>
>
read()
{
return std::move(std::make_unique<T, D<T>>(readFromFile<T>()));
}
The latter method is the one that I am trying to call.
When I write something like this:
std::unique_ptr<A> AfromFile = fileStreamer.read<std::unique_ptr<A>>()
compiler tries to compile it with the first method (template <typename T> T read() {...}) and the compilation fails. I could make this work if I made unique_ptr object first and than do the copy assignment to *unique_ptr<A> object but this is no good for me because i use some macro over those two functions and I cannot make unique_ptr<A> object or object A it self prior to calling the macro. Just for info I am using Visual Studio 2015.
Is there any way to make this work without any significant modification? I also found one suggestion that basically says you have to add a pointer parameter to one function and then call it with static_cast<Obj>(nullptr) as an argument but this does not count in my example.
Thanks for your help.
Update:
I just want to make a remark that all solutions below did work for me however the easiest way to fix my problem was solution provided by Barry.
Thx again for helping me!
It seems you want partial specialization, and as partial specialization on function is not possible, you may forward to class:
template <typename T> struct helper
{
T operator() const
{
T obj;
obj.readFromFile<T>();
return obj;
}
};
template <typename T, typename D>
struct helper<std::unique_ptr<T, D>>
{
std::unique_ptr<T, D> operator() const
{
return std::make_unique<T, D>(readFromFile<T>());
}
};
template <typename T>
T read()
{
return helper<T>{}();
}
The problem is, while I understand your intent of:
std::unique_ptr<A> AfromFile = fileStreamer.read<std::unique_ptr<A>>();
You're not actually calling the function you think you are. You have two overloads of read:
template <class T> T read();
template <class T,
template<typename> class D,
template<typename, typename> class Container
> T read();
The first has one template parameter, the second has 3 (and some sfinae). But you're only calling read() with one template parameter, so the second overload - the one you want - isn't even an option.
For these cases, I like simply tag dispatching so that we can overload instead of having to specialize:
template <class T> struct tag{};
template <class T> T read() { return read(tag<T>{}); }
template <class T>
T read(tag<T> ) {
T obj;
obj.readFromFile<T>();
return obj; // <== NB: no move() here! That inhibits RVO
}
template <class T, class D>
std::unique_ptr<T, D> read(tag<std::unique_ptr<T, D>> ) {
/* unique_ptr case */
}
You cannot have two overloads of a function which only differ by return type. You must use SFINAE to make sure only one is enabled for any given template parameter.
The way you are trying to deduce the template parameters in the second overload is wrong. Currently, you have to specify T, D and ContainerType when you call the function. I sense you probably want to pass just one type and then deduce whether it is a std::unique_ptr.
You cannot call std::make_unique and specify a deleter type. You must call the std::unique_ptr constructor with a newly created object.
You don't need to explicitly move the returned std::unique_ptr.
This is one way to do what you want.
#include <memory>
#include <type_traits>
template<typename T>
T readFromFile() { return T(); }
template<typename T, typename D>
void helper(std::unique_ptr<T, D>);
template<typename T, typename = void>
struct is_unique_ptr : std::false_type {};
template<typename T>
struct is_unique_ptr<T, decltype(helper(std::declval<T>()))> : std::true_type {};
template<typename T, typename = std::enable_if_t<!is_unique_ptr<T>::value>>
T read()
{
return readFromFile<T>();
}
template<typename P, typename = std::enable_if_t<is_unique_ptr<P>::value>, typename = void>
P read()
{
using T = typename P::element_type;
return P(new T(readFromFile<T>()));
}
int main()
{
read<std::unique_ptr<int>>();
read<int>();
}

Disallow function template instantiation with iterator parameter

I have a function template which takes a templated parameter:
template <class R>
RefT<R> make_ref(R& res) {
return RefT<R>(&res);
}
I either want to prevent R from being any kind of iterator, or, if this is easier, I want to have a overload that the compiler will prefer to use for iterators which calls make_ref again with the iterator dereferenced.
Best approach would be combining the two, so the compiler prefers using iterator specific overload, and refuses to use the non-specific version.
I would like consumers of the code to be able to call make_ref(something) without having to think about whether the something is an iterator or not - I just need to do something different if it is, and if that's not possible, give a useful error message to the consumer.
First the traits (you may have to tweak it with your requirements):
template <typename T>
auto is_iterator_impl(T* it)
-> decltype(**it, ++(*it), (*it) == (*it), std::true_type());
template <typename T>
auto is_iterator_impl(...) -> std::false_type;
template <typename T>
using is_an_iterator = decltype(is_iterator_impl<T>(0));
Note: using std::iterator_traits<IT> may be a good alternative.
With SFINAE, you may do
template <class R>
std::enable_if_t<!is_an_iterator<R>::value, RefT<R>>
make_ref(R& res) {
return RefT<R>(&res);
}
template <class R>
std::enable_if_t<is_an_iterator<R>::value && !std::is_pointer<R>::value, RefT<R>> // you may want to change return type
make_ref(R& res) {
// Implementation for iterator
}
template <class R>
std::enable_if_t<std::is_pointer<R>::value, RefT<R>> // you may want to change return type
make_ref(R& res) {
// Implementation for iterator
}
Note: as you want to manage pointer differently, I also use std::is_pointer in addition to the custom is_an_iterator.
Note: The conditions should not have overlap, else you have conflict.
Live Demo
I used is_iterator from here: https://stackoverflow.com/a/4336298/678093
This traits struct is used with SFINAE to only enable make_ref for non-iterator types:
#include <type_traits>
template<class T>
struct is_iterator
{
static T makeT();
typedef void * twoptrs[2]; // sizeof(twoptrs) > sizeof(void *)
static twoptrs & test(...); // Common case
template<class R> static typename R::iterator_category * test(R); // Iterator
template<class R> static void * test(R *); // Pointer
static const bool value = sizeof(test(makeT())) == sizeof(void *);
};
// just to make it compile
template <typename R>
struct RefT{};
template <class R, typename std::enable_if<!is_iterator<R>::value>::type* = nullptr>
RefT<R> make_ref(R& res)
{
return RefT<R>(&res);
}
int main()
{
int* a;
make_ref(a); // fails to compile
int b;
make_ref(b); // compiles once RefT is correct
return 0;
}
An alernative solution is to use std::iterator_traits:
template <class R, typename std::enable_if<std::is_same<typename std::iterator_traits<R>::value_type, void>::value>::type* = nullptr>
RefT<R> make_ref(R& res)
{
return RefT<R>(&res);
}
This could also be done by using SFINAE with std::iterator_traits, would handle all cases that previous answers handle (pointers and types having internal iterator_category typedef) but:
no need to write your own traits (like is_iterator) to do this, or at least most of the template machinery is encapsulated in iterator_traits
could also handle potential user defined iterators that were having their own iterator_traits specialization without using the generic iterator_category typedef, not sure if this relevant/legal technique but definitely possible

signed/unsigned trait programming

I'm starting to learn about traits and templates in c++. What I'm wondering is is it possible to create templates for signed/unsigned integral types. The idea is that the normal class would (probably) be implemented for singed integer types, and the variation for unsigned integer types. I tried:
template <typename T>
class FXP<T>
{ ... };
template <typename T>
class FXP<unsigned T>
{ ... };
but this does not compile.
I even came across:
std::is_integral
std::is_signed
std::is_unsigned
So, how do I put these in action to define a class that only supports these two variants?
In this case, there's a few ways to go about it, but my favorite for cases where there's a limited number of variants (e.g., a boolean or two saying which way it should behave), partial specialization of a template is usually the best way to go:
// Original implementation with default boolean for the variation type
template <typename T, bool is_unsigned = std::is_unsigned<T>::value>
class FXP {
// default implementation here
};
Your next step is to then provide a partial specialization that takes the typename T, but only works for a specific variant of the template parameters (e.g. true or false).
template <typename T>
class FXP<T, false> {
// partial specialization when is_unsigned becomes false
};
template <typename T>
class FXP<T, true> {
// partial specialization when is_unsigned becomes true
};
In this case, if you write a default implementation, you only need to make a specialization for the case that's non-default (like the true case).
Here's an example, where the default case gets overridden by a specialized template parameter:
http://coliru.stacked-crooked.com/a/bc761b7b44b0d452
Note that this is better only for smaller cases. If you need complex tests, you're better off using std::enable_if and some more complicated template parameters (like in DyP's answer).
Good luck!
With an additional template parameter:
#include <iostream>
#include <type_traits>
template <typename T, class X = void>
struct FXP
{
// possibly disallow using this primary template:
// static_assert(not std::is_same<X, X>{},
// "Error: type neither signed nor unsigned");
void print() { std::cout << "non-specialized\n"; }
};
template <typename T>
struct FXP< T, typename std::enable_if<std::is_signed<T>{}>::type >
{ void print() { std::cout << "signed\n"; } };
template <typename T>
struct FXP< T, typename std::enable_if<std::is_unsigned<T>{}>::type >
{ void print() { std::cout << "unsigned\n"; } };
struct foo {};
int main()
{
FXP<foo>().print();
FXP<int>().print();
FXP<unsigned int>().print();
}