Passing result of std::bind to std::function "overloads" - c++

I have problem similar to Passing different lambdas to function template in c++ but now with wrappers created by std::bind instead of lambdas.
I have two overloads of method Add that take different forms of std::function:
template<typename T>
struct Value
{
T value;
};
template <typename T>
void Add(Value<T> &value, function<bool()> predicate)
{
}
template <typename T>
void Add(Value<T> &value, block_deduction<function<bool(const Value<T> &)>> predicate)
{
}
This now works fine with lambdas but fails with functors bound with std::bind:
struct Predicates
{
bool Predicate0() { return true; }
bool Predicate1(const Value<int> &) { return true; }
};
Predicates p;
Add(i, std::bind(&Predicates::Predicate0, &p));
fails with
error C2668: 'Add': ambiguous call to overloaded function
and
Add(i, std::bind(&Predicates::Predicate1, &p, _1));
fails with static assert (Visual C++ 2015, Update 3):
tuple index out of bounds
Is there a way to make it work both with lambdas and bound functors? I would think of using SFINAE to enable the individual overload based on is_bindable_expression and checking the argument type but I'm failing to put it together.

Stop using std::bind. It is a mess of random features and quirks.
Todays quirk is that std::bind will accept an unlimited number of arguments and discard any extra ones. Tomorrow you might run into the fact that passing std::bind result to std::bind does strange magic.
std::bind was ported over to boost at the same time lambdas where added to the language. Lambdas solve almost every problem bind does in just as clear syntax and fails to have the myraid of quirks bind does, especially post C++14 when auto lambdas are available. (Most C++11 compilers also supported auto lambda).
You can write functions so that one or the other is the preferred overload when they both apply. But doing so adds a pile of noise to your interface, and in this case about the only reason why you'd want that preference is because std::bind is doing something stupid.
Engineering around a poorly designed bit of std library is not worth it. Simply stop using that poorly designed bit of std library, or at point of use cast explicitly.
Failing that, do this:
template <class T, class F,
std::enable_if_t<
std::is_convertible<
std::result_of_t<std::decay_t<F> const&(Value<T> const&)>,
bool
>{}, int
> = 0
>
void Add(Value<T> &value, F&& f)
{
// do pass f Value<T>
}
template <class T, class F,
std::enable_if_t<
!std::is_convertible<
std::result_of_t<std::decay_t<F> const&(Value<T> const&)>,
bool
>{}
&& std::is_convertible<
std::result_of_t<std::decay_t<F> const&()>,
bool
>{}, int
> = 0
>
void Add(Value<T> &value, F&& f)
{
// do not pass f Value<T>
}
where we throw some nasty SFINAE detection on which of the two overloads you want to use, and explicitly prefer one.
This is not worth it.

I don't think you can do what you want.
You can use is_bind_expression to check if your argument is a type produced by a call to std::bind, but there is no way to tell how many arguments the callable expects. As cpplearned mentioned in the comments, this is a feature of std::bind:
If some of the arguments that are supplied in the call to g() are not
matched by any placeholders stored in g, the unused arguments are
evaluated and discarded.
That means that both overloads are equally valid.
If you don't mind sharing the same overload for all bind results, you can pass all the parameters and let them be discarded at will:
template <typename T>
void AddImpl(Value<T> &value, function<bool()> predicate, std::false_type)
{
predicate();
}
template <typename T>
void AddImpl(Value<T> &value, block_deduction<function<bool(const Value<T> &)>> predicate, std::false_type)
{
predicate(value);
}
template <typename T, typename U>
void AddImpl(Value<T>& value, U&& bind_expression, std::true_type)
{
bind_expression(value);
}
template<typename T, typename U>
void Add(T&& t, U&& u)
{
AddImpl(std::forward<T>(t), std::forward<U>(u), std::is_bind_expression<std::decay_t<U>>{});
}
demo
But this is similar to using boolean parameters. In my opinion it'd be better for readability to dispatch on properly named tags:
template <typename T>
void AddImpl(Value<T> &value, function<bool()> predicate, tag::default_)
{
predicate();
}
template <typename T>
void AddImpl(Value<T> &value, block_deduction<function<bool(const Value<T> &)>> predicate, tag::default_)
{
predicate(value);
}
template <typename T, typename U>
void AddImpl(Value<T>& value, U&& bind_expression, tag::bind)
{
bind_expression(value);
}
template<typename T, typename U>
void Add(T&& t, U&& u)
{
AddImpl(std::forward<T>(t), std::forward<U>(u), tag::get_tag<std::decay_t<U>>{});
}
with tags defined as
namespace tag
{
struct default_{};
struct bind{};
template<typename T, typename = void>
struct get_tag : default_ {};
template<typename T>
struct get_tag<T, std::enable_if_t<std::is_bind_expression<T>::value>> : bind {};
}
demo

Related

Universal reference deduction using the same_as concept

I'm trying to implement a push function for a blocking queue which accepts a universal reference as it's template parameter, but requires that the template argument be the same type as the queue's element type:
template <typename ValueType>
class shared_queue
{
public:
template <typename Arg>
requires std::same_as<Arg, ValueType>
void push(Arg&& arg);
private:
std::deque<ValueType> container_;
};
However, I'm not quite sure how is universal reference deduction supposed to work in this case, or if it works at all for that matter. The following code:
shared_queue<int> sq;
int x{ 5 };
sq.push(x); // won't compile
sq.push(5); // all good
does not compile. The compiler complains that:
I'm pretty sure I'm misunderstanding something but I don't know what.
You need to remove_reference from Arg for same_as to consider the int& to x and int the same type. You may also want to remove const in case you have const int x and pass that as a parameter. Removing both (+ volatile) can be done with std::remove_cvref_t:
template <typename Arg>
requires std::same_as<std::remove_cvref_t<Arg>, ValueType>
void push(Arg&& arg) {
container_.push_back(std::forward<Arg>(arg));
}
Another option would be to allow for any arguments that can be used to construct a ValueType:
template <class... Args>
requires std::constructible_from<ValueType, Args...>
void emplace(Args&&... args) {
container_.emplace(container_.end(), std::forward<Args>(args)...);
}

C++ template functions accepting parameters in random order

I am writing a C++ network library and would like the main (template) function to accept parameters in random order, to make it more user friendly, in the same way the CPR library does.
The template function will accept up to 10 parameters at the same time, each a different type. Is there a way to instantiate the template to accept any random order of param types, other than having to manually include code for every possibility?
For example - in this case using 3 params each a different type:
.h file
namespace foo
{
template <typename T, typename U, typename V> void do(const T& param_a, const U& param_b , const V& param_c);
};
.cpp file
template <typename T, typename U, typename V>
void foo::do(const T& param_a, const U& param_b, const V& param_c) {
//do lots of stuff
}
//instantiate to allow random param order
template void foo::do<int, std::string, long>(const int&, const std::string&, const long&);
template void foo::do<int, long, std::string>(const int&, const long&, const std::string&);
template void foo::do<int, std::string, int>(const int&, const std::string&, const int&);
//etc... to cover all possible param orders
If your goal is to match the API design of a given library, best way to learn is to dig into its source code and dissect it.
Consider this snippet of code (I'm still using CPR as an example as you mentionned it as a reference):
cpr::Session session;
session.SetOption(option1);
session.SetOption(option2);
session.SetOption(option3);
You want a method which can handle option1, option2, ... , no matter in which order they are provided. The subsequent calls to SetOption could be replaced with a single SetOptions(option3, option1, option2). Therefore we need a variadic SetOptions method:
template<typename Ts...> // important: don't specialize the possible argument types here
void SetOptions(Ts&&... ts)
{ /* do something for each param in ts... */ }
The question is "how do you call SetOption for each item inside the ts parameter-pack ?". This is a mission for std::initializer_list. You can find a simple example here.
The key here is to have an overloaded function which can handle each argument type separately (example in CPR with SetOptions). Then, inside your "permutable" function, you call the overloaded function for each of your arguments, one at a time (example in CPR, which is then used in various places).
One thing to note though is that you can pass multiple parameters of the same type. Depending on what you want to achieve, this can be an issue or not.
Also, you can call the method with unsupported argument types (matching none of your overloads), in this case the error message is not always explicit depending on which compiler you are using. This is — however — something you could overcome using static_asserts.
Is there a way to instantiate the template to accept any random order of param types, other than having to manually include code for every possibility?
You cannot do this for explicit instantiation definitions without macros, but you could use a separate approach and rely on implicit instantiations instead, using SFINAE to restrict the primary template (whose definition you move to the header file) based on two custom traits.
To begin with, given the following type sequence
template <class... Ts>
struct seq {};
we want to construct a trait that, for a given type sequence seq<T1, T2, ...> (your "10 parameter types"), denoted as s:
s shall be a subset of set of types of your choosing seq<AllowedType1, ...>, and
s shall contain only unique types.
We can implement the former as:
#include <type_traits>
template <class T, typename... Others>
constexpr bool is_same_as_any_v{(std::is_same_v<T, Others> || ...)};
template <typename, typename> struct is_subset_of;
template <typename... Ts, typename... Us>
struct is_subset_of<seq<Ts...>, seq<Us...>> {
static constexpr bool value{(is_same_as_any_v<Ts, Us...> && ...)};
};
template <typename T, typename U>
constexpr bool is_subset_of_v{is_subset_of<T, U>::value};
and the latter as
template <typename...> struct args_are_unique;
template <typename T> struct args_are_unique<T> {
static constexpr bool value{true};
};
template <typename T, typename... Ts> struct args_are_unique<seq<T, Ts...>> {
static constexpr bool value{!is_same_as_any_v<T, Ts...> &&
args_are_unique<seq<Ts...>>::value};
};
template <typename... Ts>
constexpr bool args_are_unique_v{args_are_unique<Ts...>::value};
after which we can define the primary template as
namespace foo {
namespace detail {
using MyAllowedTypeSeq = seq<int, long, std::string>; // ...
} // namespace detail
template <
typename T, typename U, typename V, typename Seq = seq<T, U, V>,
typename = std::enable_if_t<is_subset_of_v<Seq, detail::MyAllowedTypeSeq> &&
args_are_unique_v<Seq>>>
void doStuff(const T &param_a, const U &param_b, const V &param_c) {
// do lots of stuff
}
} // namespace foo
and where we may and may not use the primary template overload as follows:
int main() {
std::string s{"foo"};
int i{42};
long l{84};
foo::doStuff(s, i, l); // OK
foo::doStuff(s, l, i); // OK
foo::doStuff(l, i, s); // OK
foo::doStuff(l, s, i); // OK
// uniqueness
foo::doStuff(l, l, i); // Error: candidate template ignored
// wrong type
unsigned int ui{13};
foo::doStuff(s, ui, l); // Error: candidate template ignored
}
If types need not actually be unique (it's somewhat unclear from the question) you can simply SFINAE-constrain the primary template only on the first is_subset_of_v trait:
template <
typename T, typename U, typename V, typename Seq = seq<T, U, V>,
typename = std::enable_if_t<is_subset_of_v<Seq, detail::MyAllowedTypeSeq>>>
void do(const T &param_a, const U &param_b, const V &param_c) {
// do lots of stuff
}
Why not use the builder pattern here? You would create a foo_builder with various setXxx methods and a final build() to get the fully configured object.
Use a struct to hold all the params.
namespace foo
{
struct do_params {
int a;
long b;
std::string c;
};
void do(do_params params);
};

C++ SFINAE - Resolution priority between std::is_arithmetic and std::is_same

I'm using SFINAE to build a rudimentary serialization library.
Let's say I have a class that implements a generic process method, that reads in any type (allowing for user-extension) and serializes it. I'm using std::enable_if to specialize this method to different template argument types. Here's an example:
class OutputSerializer
{
public:
OutputSerializer(std::ostream& str) : stream(str) {}
private:
template<typename T>
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
process(T&& arg) {
stream.write(&arg, sizeof(arg));
}
//More specializations here
std::ostream& stream;
};
I want to optimize this method for booleans, by making the output stream store 1 byte, instead of sizeof(bool) bytes. Similarly to how I did before, I add a new template specialization:
class OutputSerializer
{
public:
OutputSerializer(std::ostream& str) : stream(str) {}
private:
template<typename T>
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
process(T&& arg) {
stream.write(&arg, sizeof(arg));
}
template<typename T>
typename std::enable_if<std::is_same<T, bool>::value, void>::type
process(T&& arg) {
stream.write(&arg, 1);
}
std::ostream& stream;
};
Now, a question arises. std::is_arithmetic<bool> is also supposed to return true. So which of the two specializations will be given priority during name resolution?
Keep in mind, this is only a theoretical question. I know of more ways to make sure this method does what I want it to, such as specializing the template itself for bool, like this:
template<>
void process<bool>(bool&& arg) {
stream.write(&arg, 1);
}
or by adding an extra check in the more generic case, like this:
template<typename T>
typename std::enable_if<
std::is_arithmetic<T>::value
&& !std::is_same<T, bool>::value, void>::type
process(T&& arg) {
stream.write(&arg, sizeof(arg));
}
Or at least, I'm pretty sure these would work. Feel free to call me out on it if I'm wrong. Thank you!
Neither has any sort of priority. Both templates will result in the function void process(bool) and the call will be ambiguous.
Example
Adding an explicit specialization for bool won't work either, since there's no clear base template to specialize. You need to add more conditions to the std::is_arithmetic version of the template, or better just provide a non-template overload for bool. Functions do have priority over function templates, so a non-template version will be chosen by overload resolution.
Example

Template function that matches only certain types?

I want to define a function template:
template<typename T>
void foo(T arg)
But I want T to match only certain types. Specifically, T should derive (maybe through multiple inheritance) form a certain base class. Otherwise this template shouldn't be included in the overload set.
How can I do this?
Use SFINAE with std::is_base_of:
template <typename T,
typename = std::enable_if_t<
std::is_base_of<Foo, T>::value
>>
void foo(T arg);
That will only include foo in the overload set if T inherits from Foo. Note that this includes ambiguous and inaccessible bases as well. If you want a solution that only allows for Ts that inherit publicly and unambiguously from Foo, then you can instead use std::is_convertible:
template <typename T,
typename = std::enable_if_t<
std::is_convertible<T*, Foo*>::value
>>
void foo(T arg);
Note the reversal of arguments.
Regardless of which form you pick, it can be aliased for brevity:
template <typename T>
using enable_if_foo = std::enable_if_t<std::is_base_of<Foo, T>::value>;
template <typename T,
typename = enable_if_foo<T>>
void foo(T arg);
This works because std::enable_if has a nested type named type if and only if the boolean passed in is true. So if std::is_base_of<Foo, T>::value is true, enable_if_t gets instantiated to void, as if we had written:
template <typename T,
typename = void>
void foo(T arg);
But, if T does not inherit from Foo, then the type trait will evaluate as false, and std::enable_if_t<false> is a substitution failure - there is no typename enable_if<false>::type. You might expect this to a compile error, but substitution failure is not an error (sfinae). It's just a template deduction failure. So the effect is that foo<T> is simply removed from the set of viable overload candidates in this case, no different from any other template deduction failure.
SFINAE based techniques such as the following;
template <typename T,
typename Test = std::enable_if_t<std::is_base_of<Foo, T>::value>>
void foo(T arg);
Are good to remove the function from the overload list - which would be a general case.
If you wish to keep the function in the list, and if chosen as the best overload to fail if the type matches some criteria (such as a base requirement here), the static_assert can be used;
template <typename T>
void foo(T arg)
{
static_assert(std::is_base_of<Foo, T>::value, "failed type check");
// ...
}
In C++1z with concepts lite, you can do this:
template<class T>
requires std::is_base_of<Foo, T>{}()
void foo(T arg) {
}
under the current (experimental) implementation. Which is pretty clean and clear. There may be a way to do something like:
template<derived_from<Foo> T>
void foo(T arg) {
}
but I haven't worked it out. You can definitely do:
template<derived_from_foo T>
void foo(T arg){
}
where we have a custom concept called derived_from_foo that applies iff the type is derived from foo. What I don't know how to do is template concepts -- concepts generated from template type parameters.
In C++14, here are two methods. First, normal SFINAE:
template<class T,
class=std::enable_if_t<std::is_base_of<Foo, T>{}>
>
void foo(T arg) {
}
here we create a template that deduces the type T from its argument. It then tries to deduce its second type argument from the first argument.
The second type argument has no name (hence class=), because we are only using it for a SFINAE test.
The test is enable_if_t< condition >. enable_if_t< condition > generates the type void if condition is true. If condition is false, it fails in "the immediate context", generating a substitution failure.
SFINAE is "Substitution failure is not an error" -- if your type T generates a failure in the "immediate context" of the function template signature, this doesn't generate a compile-time error, but instead results in the function template not being considered a valid overload in this case.
"Immediate context" is a technical term here, but basically it means the error has to be "early enough" to be caught. If it requires compiling bodies of functions to find the error, that is not in "the immediate context".
Now, this isn't the only way. I personally like hiding my SFINAE code behind a gloss of respectability. Below, I use tag dispatching to "hide" the failure somewhere else, instead of putting it right up front in the function signature:
template<class T>
struct tag {
using type=T;
constexpr tag(tag const&) = default;
constexpr tag() = default;
template<class U,
class=std::enable_if_t<std::is_base_of<T,U>{}>
>
constexpr tag(tag<U>) {}
};
struct Base{};
struct Derived:Base{};
template<class T>
void foo( T t, tag<Base> = tag<T>{} ) {
}
here we create a tag dispatch type, and it allows conversion to base. tag lets us worth with types as values, and use more normal C++ operations on them (instead of template-like metaprogramming <>s all over the place).
We then give foo a second argument of type tag<Base>, then construct it with a tag<T>. This fails to compile if T is not a derived type from Base.
live example.
The nice thing about this solution is that the code that makes it not work seems more intuitive -- tag<Unrelated> cannot convert to tag<Base>. This does not, however, prevent the function from being considered for overload resolution, which can be a problem.
A way with less boiler plate is:
template<class T>
void foo( T t, Base*=(T*)0 ) {
}
where we use the fact that pointers can be converted iff there is a derivation relationship between them.
In C++11 (and without constexpr support), we first write a helper:
namespace notstd {
template<bool b, class T=void>
using enable_if_t=typename std::enable_if<b,T>::type;
}
then:
template<class T,
class=notstd::enable_if_t<std::is_base_of<Foo, T>::value>
>
void foo(T arg) {
}
if you don't like the helper, we get this ugly extra:
template<class T,
class=typename std::enable_if<std::is_base_of<Foo, T>::value>::type
>
void foo(T arg) {
}
the second C++14 technique above can also be translated to C++11.
You can write an alias that does the test if you want:
template<class U>
using base_test=notstd::enable_if_t<std::is_base_of<Base, U>::value>;
template<class T,
class=base_test<T>
>
void foo(T arg) {
}

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