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)...);
}
Related
I have a function that needs to take shared ownership of an argument, but does not modify it.
I have made the argument a shared_ptr<const T> to clearly convey this intent.
template <typename T>
void func(std::shared_ptr<const T> ptr){}
I would like to call this function with a shared_ptr to a non-const T. For example:
auto nonConstInt = std::make_shared<int>();
func(nonConstInt);
However this generates a compile error on VC 2017:
error C2672: 'func': no matching overloaded function found
error C2784: 'void func(std::shared_ptr<const _Ty>)': could not deduce template argument for 'std::shared_ptr<const _Ty>' from 'std::shared_ptr<int>'
note: see declaration of 'func'
Is there a way to make this work without:
Modifying the calls to func. This is part of a larger code refactoring, and I would prefer not to have to use std::const_pointer_cast at every call site.
Defining multiple overloads of func as that seems redundant.
We are currently compiling against the C++14 standard, with plans to move to c++17 soon, if that helps.
template <typename T>
void cfunc(std::shared_ptr<const T> ptr){
// implementation
}
template <typename T>
void func(std::shared_ptr<T> ptr){ return cfunc<T>(std::move(ptr)); }
template <typename T>
void func(std::shared_ptr<const T> ptr){ return cfunc<T>(std::move(ptr)); }
this matches how cbegin works, and the "overloads" are trivial forwarders with nearly zero cost.
Unfortunately, there is no good solution to what you desire. The error occurs because it fails to deduce template argument T. During argument deduction it attempts only a few simple conversations and you cannot influence it in any way.
Think of it: to cast from std::shared_ptr<T> to some std::shared_ptr<const U> it requires to know U, so how should compiler be able to tell that U=T and not some other type? You can always cast to std::shared_ptr<const void>, so why not U=void? So such searches aren't performed at all as in general it is not solvable. Perhaps, hypothetically one could propose a feature where certain user-explicitly-declared casts are attempted for argument deduction but it isn't a part of C++.
Only advise is to write function declaration without const:
template <typename T>
void func(std::shared_ptr<T> ptr){}
You could try to show your intent by making the function into a redirection like:
template <typename T>
void func(std::shared_ptr<T> ptr)
{
func_impl<T>(std::move(ptr));
}
Where func_impl is the implementation function that accepts a std::shared_ptr<const T>. Or even perform const cast directly upon calling func_impl.
Thanks for the replies.
I ended up solving this a slightly different way. I changed the function parameter to just a shared_ptr to any T so that it would allow const types, then I used std::enable_if to restrict the template to types that I care about. (In my case vector<T> and const vector<T>)
The call sites don't need to be modified. The function will compile when called with both shared_ptr<const T> and shared_ptr<T> without needing separate overloads.
Here's a complete example that compiles on VC, GCC, and clang:
#include <iostream>
#include <memory>
#include <vector>
template<typename T>
struct is_vector : public std::false_type{};
template<typename T>
struct is_vector<std::vector<T>> : public std::true_type{};
template<typename T>
struct is_vector<const std::vector<T>> : public std::true_type{};
template <typename ArrayType,
typename std::enable_if_t<is_vector<ArrayType>::value>* = nullptr>
void func( std::shared_ptr<ArrayType> ptr) {
}
int main()
{
std::shared_ptr< const std::vector<int> > constPtr;
std::shared_ptr< std::vector<int> > nonConstPtr;
func(constPtr);
func(nonConstPtr);
}
The only downside is that the non-const instantiation of func will allow non-const methods to be called on the passed-in ptr. In my case a compile error will still be generated since there are some calls to the const version of func and both versions come from the same template.
As the const is only for documentation, make it a comment:
template <class T>
void func(std::shared_ptr</*const*/ T> p) {
}
You could additionally delegate to the version getting a pointer to constant object if the function is hefty enough to make it worthwhile:
template <class T>
void func(std::shared_ptr</*const*/ T> p) {
if (!std::is_const<T>::value) // TODO: constexpr
return func<const T>(std::move(p));
}
No guarantee the compiler will eliminate the move though.
You certainly don't want to be modifying the call sites, but you sure can be modifying the functions themselves - that's what you implied in the question anyway. Something had to be changed somewhere, after all.
Thus:
In C++17 you could use deduction guides and modify call sites, but in a less intrusive manner than with a cast. I'm sure a language lawyer can pitch in about whether adding a deduction guide to the std namespace is allowed. At the very least we can limit the applicability of those deduction guides to the types we care about - it won't work for the others. That's to limit potential for mayhem.
template <typename T>
class allow_const_shared_ptr_cast : public std::integral_constant<bool, false> {};
template <typename T>
static constexpr bool allow_const_shared_ptr_cast_v = allow_const_shared_ptr_cast<T>::value;
template<>
class allow_const_shared_ptr_cast<int> : public std::integral_constant<bool, true> {};
template <typename T>
void func(std::shared_ptr<const T> ptr) {}
namespace std {
template<class Y> shared_ptr(const shared_ptr<Y>&) noexcept
-> shared_ptr<std::enable_if_t<allow_const_shared_ptr_cast_v<Y>, const Y>>;
template<class Y> shared_ptr(shared_ptr<Y>&&) noexcept
-> shared_ptr<std::enable_if_t<allow_const_shared_ptr_cast_v<Y>, const Y>>;
}
void test() {
std::shared_ptr<int> nonConstInt;
func(std::shared_ptr(nonConstInt));
func(std::shared_ptr(std::make_shared<int>()));
}
std::shared_ptr is certainly less wordy than std::const_pointer_cast<SomeType>.
This should not have any performance impact, but sure modifying the call sites is a pain.
Otherwise there's no solution that doesn't involve modifying the called function declarations - but the modification should be acceptable, I think, since it's not any more wordy than what you had already:
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
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) {
}
I have some difficulties with perfect forwarding.
Here is my current level of understanding : glue Template + rvalue reference + std::forward and a special magical mode get activated where template deduction rules have not the same meaning as usual, but are crafted to allow perfect forwarding. Example :
template <typename T>
void outer(T&& t)
{
inner(std::forward<T>(t)); // perfect forwarding activated
}
But what happen if T is actually a templated class ?
For example, how can I perfect forward a std::tuple ? If use a T&& as aboce I will lost all type information of the objects contained in the tuple.
However the following code can't work :
template <typename... Args>
void outer(std::tuple<Args...>&& t)
{
inner(std::forward<std::tuple<Args...>>(t));
use_args_types_for_something_else<Args...>(); // I need to have Args available
}
int main()
{
std::tuple<int, double, float> t(4, 5.0, 4.0f);
outer(t);
}
Last gcc snapshot says :
error: cannot bind 'std::tuple<int, double, float> lvalue to
std::tuple<int, double, float>&&
So clearly, we are still in the general, non-template case where lvalue can't bind to rvalue reference. "Perfect forwading mode" is not activated
So I tried to be sneaky and pass my tuple as a template template :
template <
typename... Args
template <typename...> class T
>
void outer(T<Args...>&& t)
{
inner(std::forward<T<Args...>>(t));
use_args_type_for_something_else<Args...>();
}
But I still get the same error.
Perfect forwarding works only if the type of the parameter is a template type for the function, so the only way to achieve perfect forwarding is like in your first example:
template <typename T>
void outer(T&& t)
{
inner(std::forward<T>(t)); // perfect forwarding activated
}
The above works because it is a special case where T is deduced as SomeType& or SomeType&&.
This, however, does not mean that the type information for the tuple elements is lost for good. It is still retrievable (although I don't think you can typedef a variadic template pack). For example, you can still call use_args_types_for_something_else like this:
template <class T>
struct call_uses_args;
template <class ...Args>
struct call_uses_args<std::tuple<Args...>>
{
void call() const { use_args_types_for_something_else<Args...>(); }
};
template <typename TupleT>
void outer(TupleT&& t)
{
inner(std::forward<TupleT>(t));
call_uses_args<typename std::remove_reference<TupleT>::type>().call();
}
There might be no good general solution, though, but hopefully such situations are rare. (E.g, in this particular example, it might be simpler just to overload outer.)
Why can't the compiler figure out these template parameters? Is there a way to make it do so?
(I'm using Visual Studio 2010.)
template<typename T, typename TFunc>
void call(TFunc func) { func(T()); }
void myfunc(void *) { }
int main() { call(myfunc); }
T appears nowhere in the parameter list so T cannot be deduced from the function arguments. All types to be deduced must appear in deduced contexts in the parameter list. For example,
template <typename TReturn, typename TParameter>
void call(TReturn (*f)(TParameter))
{
f(TParameter());
}
Template parameter deduction for function templates only works based on function arguments, nothing else. The function definition is never looked at for the purpose of determining the template parameters, so your parameter T cannot possibly be deduced.
You could remedy your situation by incorporating the type into the function signature: Since you expect the outer function to be called with a function itself, make that explicit:
template <typename T> void foo(void(*f)(T))
{
T x;
f(x);
// ...
}
Combine function overloading with functors, and it becomes impossible in the general case to determine what arguments can be passed to a callable entity.
Consider, for example
struct FunctorExample {
void operator()(int x) {...}
std::string operator()(const std::string& ) {...}
};
If there were some way to coax the compiler to pattern match on arguments, it would have to have undefined or error behavior when applied to FunctorExample.
Instead, the trend seems to be that when you want to template metaprogram with functors, you specify the functor and argument list. Examples (off the top of my head) being boost::result_of and boost::fusion.
Edit: That said, if you're willing to restrict your attention somewhat, and you can use some C++11 syntax (decltype), you can arrange to introspect a bit more:
// Support functors with a very simple operator():
template <typename T> struct argument :
public argument<decltype(&T::operator())> {};
// Pointers to member functions
template <typename C, typename R, typename A> struct argument<R(C::*)(A)>
{typedef A type;};
// Function types
template <typename R, typename A> struct argument<R(A)> {typedef A type;};
// Function pointer types.
template <typename R, typename A> struct argument<R(*)(A)> {typedef A type;};
// Now for call:
template <typename FuncType>
void call(FuncType func) {
typedef typename argument<FuncType>::type Arg;
func(Arg());
}
// example:
class FunctorInt {public: int operator()(int ) {return 0;};};
void myfunc(void *) {}
int main() {
call(myfunc);
call(FunctorInt());
}
Variadic templates could be used to expand this stuff to support more than one argument.