I'm trying to implement bind function from boost library.
Below you can see the main struct bind_t with defined operator().
My question is as follows: Why should we specify in decltype in returning type of operator() returning type of call() explicitly as member function (if I remove this-> before call, the template argument deduction fails in g++.)
Also interesting, that using clang++ there's no such problem.
I have no idea, why this happens.
template <typename F, typename ... P>
struct bind_t {
private:
std::tuple<typename holder<P>::type...> p;
F func;
template <size_t ... N, typename ... Args>
auto call(index_list<N ...>, Args const& ... args) const -> decltype(func(std::get<N>(p)(args...)...)) {
return func(std::get<N>(p)(args...)...);
}
public:
bind_t(F f, P ... p):
p(std::move(p)...),
func(std::move(f))
{}
template <typename ... Args>
auto operator()(Args const& ... args) const -> decltype(this->call(typename indices_by_num<sizeof...(P)>::type(), args...)) {
typename indices_by_num<sizeof...(P)>::type indices;
return call(indices, args...);
}
};
full source of implementation
simple usecase
This is a gcc bug and is documented in the bug report decltype needs explicit 'this' pointer in member function declaration of template class with trailing return type which says:
When using trailing return-type for member functions of a template
class, the 'this' pointer must be explicitly mentioned. This should
not be necessary (The implicit 'this' works with a non-template
class).
Example:
template <typename T>
struct DecltypeConstThis {
T f() const { return T{}; }
auto g() -> decltype(this->f()) { return this->f(); }
auto h() const -> decltype(f()) { return f(); } // this should work the same as g() above (with implicit 'this')
};
struct Working {
int f() const { return 0; }
auto h() const -> decltype(f()) { return 0; }
};
int main() {
Working w;
w.h();
DecltypeConstThis<int> d;
d.g();
d.h();
return 0;
}
The report was marked as fixed and it looks like this works starts working in gcc 5.1 (see it live).
Related
Using C++ 17. I have the following:
template <typename T>
using ptr_t = std::shared_ptr<const T>;
class some_type;
class A { some_type foo() const; }
class B { some_type foo() const; }
class C { some_type foo(int) const; }
std::variant<ptr_t<A>, ptr_t<B>, ptr_t<C>>;
A variant holds shared_ptr(s) to different types. All expected to have function foo() that may be void or take a parameter. I will then have a visitor that would correctly dispatch foo, something like this (conceptually):
struct visitor
{
template <typename T>
ptr_t<some_type> operator()(const T& config) const
{
if constexpr (// determine if foo() of the underlying type of a shared_ptr can be called with int param)
return config->foo(15);
else
return config->foo();
}
is there a way to say this? I tried various ways but can't come with something that compiles. Template parameter, T, is ptr_t<A|B|C>.
std::is_invocable_v<Callable, Args...> is the way to go. Unfortunatelly, it will not compile just like that with if constexpr. It will either fail because "there is no operator()() overload", or there is no overload for operator taking Args....
I suggest you add a wrapper class for a callable and use it with a specialized alias template of std::variant instead of writing your own visitor. It will allow you to use std::visit seamlessly.
#include <type_traits>
#include <variant>
template <typename Callable>
class wrapped_callable
{
Callable c;
public:
wrapped_callable(Callable c)
: c(c)
{}
template <typename ... Args>
constexpr decltype(auto) operator()(Args &&... args) const
{
return _invoke(std::is_invocable<Callable, Args...>{}, c, std::forward<Args>(args)...);
}
private:
using _invocable = std::true_type;
using _non_invocable = std::false_type;
template <typename T, typename ... Args>
constexpr static decltype(auto) _invoke(_invocable, const T& t, Args &&... args)
{
return t(std::forward<Args>(args)...);
}
template <typename T, typename ... Args>
constexpr static decltype(auto) _invoke(_non_invocable, const T& t, Args ... args)
{
return t();
}
};
template <typename ... T>
using variant_callable = std::variant<wrapped_callable<T>...>;
struct int_callable
{
int operator()(int i) const
{
return i;
}
};
struct non_callable
{
int operator()() const
{
return 42;
}
};
#include <iostream>
int main()
{
using variant_t = variant_callable<int_callable, non_callable>;
// 23 is ignored, 42 is printed
std::visit([](const auto &callable){
std::cout << callable(23) << '\n';
}, variant_t{non_callable()});
// 23 is passed along and printed
std::visit([](const auto &callable){
std::cout << callable(23) << '\n';
}, variant_t{int_callable()});
}
Program returned: 0
42
23
https://godbolt.org/z/e6GzvW6n6
But The idea is not to have any specialization for all types in a variant as it will then require changing the visitor code every time a new type is added.
That is what template alias of std::variant<wrapped_callable<T>...> for. You just add append a new type to the list, that's it.
Take notice, that it does not depend on if constexpr. So if you manage to provide your own variant and is_invocable_v, it will work for C++14. For C++11 possibly, but some modifications regarding constexpr functions might be needed.
Of course you can implement your visitor in the same manner if you want to use std::shared_ptr istead of a callable.
But I don't see any reason to use:
visitor + smart pointer. Just use a smart pointer - it will give you runtime polymorphism in a "classic" way (via virtual inheritence)
why std::shared_ptr? Do you really need to share the ownership? Just stick with std::unique_ptr
I would like to implement a specialized invoke with extra conversion on the arguments using C++11/14. Basically, the idea is:
struct Foo {
private:
void* ptr;
public:
void* get();
};
template <typename F, typename... Args>
auto convert_invoke(F&& f, Args&&... args) {
// not sure how to do here with C++11/14
}
// caller side
int simple(float* f1, size_t N) {
// doing something interesting
}
// ideally I would like to call the following:
Foo foo;
size_t n = 10;
convert_invoke(simple, foo, n); // internally calls simple((float*)foo.get(), n);
The idea here is when the argument is of type Foo, I will do some specialized processing like getting the void* pointer and cast it to the corresponding argument type defined in simple. How can I implement this in convert_invoke?
You might do something like:
// Wrapper to allow conversion to expected pointer.
struct FooWrapper
{
void* p;
// Allow conversion to any pointer type
template <typename T>
operator T* () { return (T*) p; }
};
// Identity function by default
template <typename T>
decltype(auto) convert(T&& t) // C++14
// auto convert(T&& t) -> decltype(std::forward<T>(t)) // C++11
{ return std::forward<T>(t); }
// special case for Foo, probably need other overloads for Foo&& and cv versions
auto convert(Foo& foo) { return FooWrapper{foo.get()}; }
// Your function
template <typename F, typename... Args>
auto convert_invoke(F&& f, Args&&... args) {
return f(convert(std::forward<Args>(args))...);
}
Demo
I am attempting to create a class template whose constructor(s) can take any kind of function as argument, that is, it takes a function pointer (which can be a member function pointer) and the corresponding function arguments. Additionally, there should be a static_assert that checks whether the function return type (taken from the function pointer) matches the class template parameter type. Thus, the code should look something like this:
template <class ReturnType>
struct Bar
{
template <class RetType, class ... ParamType>
Bar<ReturnType>(RetType (* func)(ParamType ...), ParamType && ... args) :
package_(std::bind(func, std::forward<ParamType>(args) ...)),
function_([this] { package_(); }),
future_(package_.get_future())
{
static_assert(std::is_same<ReturnType, RetType>::value,
"Type mismatch between class parameter type and constructor parameter type");
}
template <class RetType, class ObjType, class ... ParamType>
Bar<ReturnType>(RetType (ObjType::* func)(ParamType ...), ObjType * obj, ParamType && ... args) :
package_(std::bind(func, obj, std::forward<ParamType>(args) ...)),
function_([this] { package_(); }),
future_(package_.get_future())
{
static_assert(std::is_same<ReturnType, RetType>::value,
"Type mismatch between class parameter type and constructor parameter type");
}
std::packaged_task<ReturnType()> package_;
std::function<void()> function_;
std::future<ReturnType> future_;
};
The idea is that the code compiles for these situations, and allows for Bar::function_ to be called (through the function call operator) without errors:
struct Foo
{
int foo(int i) {
return i;
}
int foo() {
return 1;
}
};
int foo(int i)
{
return i;
}
int foo()
{
return 1;
}
int main()
{
Foo f = Foo();
Bar<int> b1(&Foo::foo, &f, 1);
Bar<int> b2(&Foo::foo, &f);
Bar<int> b3(foo, 1);
Bar<int> b4(foo);
return 0;
}
Unfortunately, I have close to zero experience with template metaprogramming, and even though I have ran over several questions here in SO, and attempted several ways of solving my problem, such as using a more generalized approach to the constructor
template <class RetType, class ... ParamType>
Bar<ReturnType>(RetType func, ParamType && ... args)
and combining it with type_traits to determine the return type), I have yet to find a way to make this work. What changes can I do to the constructor(s) that allow this functionality?
Edit:
max66's answer solved my original problem, however, a new one arose, which I hadn't considered in the previous question. I also want to be able to pass variables to the constructor, like so:
int main()
{
Foo f = Foo();
int i = 1;
Bar<int> b1(&Foo::foo, &f, i); // Error
Bar<int> b2(&Foo::foo, &f, 1); // Ok
Bar<int> b3(&Foo::foo, &f); // Ok
Bar<int> b4(foo, i); // Error
Bar<int> b5(foo, 1); // Ok
Bar<int> b6(foo); // Ok
return 0;
}
however, as it is, a compiler error shows up in the cases marked with Error. I am guessing this is because the parameter func in the constructor uses ParamType to determine its type (which doesn't match with the actual ParamTypes in the case of b1 and b4), but I have no idea how to solve this...
You probably want to use std::invoke. It handles working with member function pointers and regular functions for you.
As an outline of the sort of stuff you can do:
#include <functional>
#include <type_traits>
#include <utility>
template<typename F>
class Bar
{
F f_;
public:
template<typename TF>
Bar(TF && f)
: f_{ std::forward<TF>(f) }
{}
template<typename... Args>
decltype(auto) operator()(Args &&... args) {
return std::invoke(f_, std::forward<Args>(args)...);
}
};
template<typename F>
auto make_bar(F && f)
{
return Bar<std::decay_t<F>>{ std::forward<F>(f) };
}
It can be used like so:
auto b1 = make_bar(&f);
auto result = b1(myArg1, myArg2); // etc
auto b2 = make_bar(&Foo::fn);
auto result = b1(foo, arg1);
In the very least, I would recommend having Bar take the function object type as a template parameter so that you don't have to use std::function, but if you do want to use the exact calling syntax you have, it can be done using std::invoke and std::invoke_result as well.
Sorry but... if you want that the return type of the funtion is equal to the template parameter of the class... why don't you simply impose it?
I mean... you can use ReturnType instead of RetType, as follows
template <typename ReturnType>
struct Bar
{
template <typename ... ParamType>
Bar<ReturnType> (ReturnType (*func)(ParamType ...), ParamType && ... args)
: package_(std::bind(func, std::forward<ParamType>(args) ...)),
function_([this] { package_(); }),
future_(package_.get_future())
{ }
template <typename ObjType, typename ... ParamType>
Bar<ReturnType> (ReturnType (ObjType::* func)(ParamType ...),
ObjType * obj, ParamType && ... args)
: package_(std::bind(func, obj, std::forward<ParamType>(args) ...)),
function_([this] { package_(); }),
future_(package_.get_future())
{ }
-- EDIT --
To solve the second problem, IF your not interested in moving parameters, you can throw away std::forward and &&, and simply write
template <typename ReturnType>
struct Bar
{
template <typename ... ParamType>
Bar<ReturnType> (ReturnType (*func)(ParamType ...),
ParamType const & ... args)
: package_(std::bind(func, args...)),
function_([this] { package_(); }),
future_(package_.get_future())
{ }
template <typename ObjType, typename ... ParamType>
Bar<ReturnType> (ReturnType (ObjType::* func)(ParamType ...),
ObjType * obj, ParamType const & ... args)
: package_(std::bind(func, obj, args...)),
function_([this] { package_(); }),
future_(package_.get_future())
{ }
I am trying to implement a resource protection class which would combine data along with a shared mutex (actually, QReadWriteLock, but it's similar). The class must provide the method to apply a user-defined function to the data when the lock is acquired. I would like this apply method to work differently depending on the function parameter (reference, const reference, or value). For example, when the user passes a function like int (const DataType &) it shouldn't block exclusively as we are just reading the data and, conversely, when the function has the signature like void (DataType &) that implies data modification, hence the exclusive lock is needed.
My first attempt was to use std::function:
template <typename T>
class Resource1
{
public:
template <typename Result>
Result apply(std::function<Result(T &)> &&f)
{
QWriteLocker locker(&this->lock); // acquire exclusive lock
return std::forward<std::function<Result(T &)>>(f)(this->data);
}
template <typename Result>
Result apply(std::function<Result(const T &)> &&f) const
{
QReadLocker locker(&this->lock); // acquire shared lock
return std::forward<std::function<Result (const T &)>>(f)(this->data);
}
private:
T data;
mutable QReadWriteLock lock;
};
But std::function doesn't seem to restrict parameter constness, so std::function<void (int &)> can easily accept void (const int &), which is not what I want. Also in this case it can't deduce lambda's result type, so I have to specify it manually:
Resource1<QList<int>> resource1;
resource1.apply<void>([](QList<int> &lst) { lst.append(11); }); // calls non-const version (ok)
resource1.apply<int>([](const QList<int> &lst) -> int { return lst.size(); }); // also calls non-const version (wrong)
My second attempt was to use std::result_of and return type SFINAE:
template <typename T>
class Resource2
{
public:
template <typename F>
typename std::result_of<F (T &)>::type apply(F &&f)
{
QWriteLocker locker(&this->lock); // lock exclusively
return std::forward<F>(f)(this->data);
}
template <typename F>
typename std::result_of<F (const T &)>::type apply(F &&f) const
{
QReadLocker locker(&this->lock); // lock non-exclusively
return std::forward<F>(f)(this->data);
}
private:
T data;
mutable QReadWriteLock lock;
};
Resource2<QList<int>> resource2;
resource2.apply([](QList<int> &lst) {lst.append(12); }); // calls non-const version (ok)
resource2.apply([](const QList<int> &lst) { return lst.size(); }); // also calls non-const version (wrong)
Mainly the same thing happens: as long as the object is non-const the mutable version of apply gets called and result_of doesn't restrict anything.
Is there any way to achieve this?
You may do the following
template <std::size_t N>
struct overload_priority : overload_priority<N - 1> {};
template <> struct overload_priority<0> {};
using low_priority = overload_priority<0>;
using high_priority = overload_priority<1>;
template <typename T>
class Resource
{
public:
template <typename F>
auto apply(F&& f) const
// -> decltype(apply_impl(std::forward<F>(f), high_priority{}))
{
return apply_impl(std::forward<F>(f), high_priority{});
}
template <typename F>
auto apply(F&& f)
// -> decltype(apply_impl(std::forward<F>(f), high_priority{}))
{
return apply_impl(std::forward<F>(f), high_priority{});
}
private:
template <typename F>
auto apply_impl(F&& f, low_priority) -> decltype(f(std::declval<T&>()))
{
std::cout << "ReadLock\n";
return std::forward<F>(f)(this->data);
}
template <typename F>
auto apply_impl(F&& f, high_priority) -> decltype(f(std::declval<const T&>())) const
{
std::cout << "WriteLock\n";
return std::forward<F>(f)(this->data);
}
private:
T data;
};
Demo
Jarod has given a workaround, but I'll explain why you cannot achieve that this regular way.
The problem is that:
Overload resolution prefers non-const member functions over const member functions when called from a non-const object
whatever object this signature void foo(A&) can accept, void foo(const A&) can also the same object. The latter even has a broader binding set than the former.
Hence, to solve it, you will have to at least defeat point 1 before getting to 2. As Jarod has done.
From your signatures (see my comment annotations):
template <typename F>
typename std::result_of<F (T &)>::type apply(F &&f) //non-const member function
{
return std::forward<F>(f)(this->data);
}
template <typename F>
typename std::result_of<F (const T &)>::type apply(F &&f) const //const member function
{
return std::forward<F>(f)(this->data);
}
When you call it like:
resource2.apply([](QList<int> &lst) {lst.append(12); }); //1
resource2.apply([](const QList<int> &lst) { return lst.size(); }); //2
First of all, remember that resource2 isn't a const reference. Hence, the non-const membr function of apply will always be prefered by Overload resolution.
Now, taking the case of the first call //1, Whatever that lambda is callable with, then then the second one is also callable with that object
A simplified mock-up of what you are trying to do is:
struct A{
template<typename Func>
void foo(Func&& f); //enable if we can call f(B&);
template<typename Func>
void foo(Func&& f) const; //enable if we can call f(const B&);
};
void bar1(B&);
void bar2(const B&);
int main(){
A a;
a.foo(bar1);
a.foo(bar2);
//bar1 and bar2 can be both called with lvalues
B b;
bar1(b);
bar2(b);
}
As I understand it, you want to discriminate a parameter that's a std::function that takes a const reference versus a non-constant reference.
The following SFINAE-based approach seems to work, using a helper specialization class:
#include <functional>
#include <iostream>
template<typename ...Args>
using void_t=void;
template<typename Result,
typename T,
typename lambda,
typename void_t=void> class apply_helper;
template <typename T>
class Resource1
{
public:
template <typename Result, typename lambda>
Result apply(lambda &&l)
{
return apply_helper<Result, T, lambda>::helper(std::forward<lambda>(l));
}
};
template<typename Result, typename T, typename lambda, typename void_t>
class apply_helper {
public:
static Result helper(lambda &&l)
{
std::cout << "T &" << std::endl;
T t;
return l(t);
}
};
template<typename Result, typename T, typename lambda>
class apply_helper<Result, T, lambda,
void_t<decltype( std::declval<lambda>()( std::declval<T>()))>> {
public:
static Result helper(lambda &&l)
{
std::cout << "const T &" << std::endl;
return l( T());
}
};
Resource1<int> test;
int main()
{
auto lambda1=std::function<char (const int &)>([](const int &i)
{
return (char)i;
});
auto lambda2=std::function<char (int &)>([](int &i)
{
return (char)i;
});
auto lambda3=[](const int &i) { return (char)i; };
auto lambda4=[](int &i) { return (char)i; };
test.apply<char>(lambda1);
test.apply<char>(lambda2);
test.apply<char>(lambda3);
test.apply<char>(lambda4);
}
Output:
const T &
T &
const T &
T &
Demo
The helper() static class in the specialized class can now be modified to take a this parameter, instead, and then use it to trampoline back into the original template's class's method.
As long as the capture lists of your lambdas are empty, you can rely on the fact that such a lambda decays to a function pointer.
It's suffice to discriminate between the two types.
It follows a minimal, working example:
#include<iostream>
template <typename T>
class Resource {
public:
template <typename Result>
Result apply(Result(*f)(T &)) {
std::cout << "non-const" << std::endl;
return f(this->data);
}
template <typename Result>
Result apply(Result(*f)(const T &)) const {
std::cout << "const" << std::endl;
return f(this->data);
}
private:
T data;
};
int main() {
Resource<int> resource;
resource.apply<void>([](int &lst) { });
resource.apply<int>([](const int &lst) -> int { return 42; });
}
I would like to avoid the need to specify the return type when calling a template member function. The 'decltype' keyword combined with 'auto' can accomplish this, but unfortunately we do not have a C++11 compiler for all the platforms we need to support. Qualifying the template method application with a type also works, but requires the caller to... qualify the template method with a type.
Is the following possible, with some template magic? Does boost 1.48 provide any help here?
Our actual code is leveraging boost::thread, boost::packaged_task, and boost::unique_future, but here is a contrived example:
#include <functional>
#ifdef WONT_COMPILE
struct WrapNoDecltype
{
WrapNoDecltype() {}
template<typename F>
std::result_of<F>::type // warning: 'std::result_of<_Fty>::type' : dependent name is not a type
operator()(const F& f)
{
setup();
std::result_of<F>::type result = f();
teardown();
return result;
}
void setup() { }
void teardown() { }
};
#endif
struct Wrap
{
Wrap() {}
template<typename F>
auto operator()(const F& f) -> decltype(f())
{
setup();
typename std::result_of<F()>::type result = f();
teardown();
return result;
}
void setup() { }
void teardown() { }
};
struct WrapWithReturnType
{
WrapWithReturnType() {}
template<typename RetType>
RetType
apply(const std::function<RetType(void)>& f)
{
setup();
RetType result = f();
teardown();
return result;
}
void setup() { }
void teardown() { }
};
int answer()
{
return 42;
}
int main()
{
Wrap w;
WrapWithReturnType wwr;
#ifdef WONT_COMPILE
WrapNoDecltype wna;
#endif
int i = w(answer);
int j = wwr.apply<int>(answer);
#ifdef WONT_COMPILE
int k = wna(answer);
#endif
return 0;
}
struct WrapNoDecltype
{
WrapNoDecltype() {}
// version for function references
template < typename Res >
Res operator()( Res(&f)() )
{
setup();
Res result = f();
teardown();
return result;
}
// version for everything
template < typename T >
typename std::result_of<typename std::decay<T>::type ()>::type
operator()( T const& f )
{
setup();
typename std::result_of<typename std::decay<T>::type ()>::type result = f();
teardown();
return result;
}
void setup() { }
void teardown() { }
};
As Yakk pointed out, by incorporating decay, the second version always works. The first version is much simpler but only works when passing function references.
Of course, you can also use boost::result_of or std::tr1::result_of.
As far as I can tell, if we modify your call to include a & operator, the only errors in your original code is the lack of typename when talking about dependent types, and the lack of an argument list when calling std::result_of:
struct WrapNoDecltype
{
WrapNoDecltype() {}
template < typename T >
typename std::result_of<T()>::type operator()( T const &f )
{
setup();
typename std::result_of<T()>::type result = f();
teardown();
return result;
}
};
however, std::result_of is a C++11 traits class, so if your compiler doesn't support decltype, it may not properly support std::result_of.
std::tr1::result_of may have quirks that prevent the above from working.
In the wild, a use of std::result_of on a function pointer type: http://ideone.com/dkGid8
As #DyP has noted, this only works if you call it with &f instead of f. To fix this, use std::decay like this:
struct WrapNoDecltype
{
WrapNoDecltype() {}
template < typename T >
typename std::result_of<typename std::decay<T>::type()>::type
operator()( T const &f )
{
// setup()
typename std::result_of<typename std::decay<T>::type()>::type
result = f();
// teardown()
return result;
}
};
int foo() { return 7; }
int main()
{
WrapNoDecltype test;
int x = test(foo);
}
which turns the function type into a function pointer type.
This is needed because std::result_of abuses C++ syntax. std::result_of< Func_Type ( Args... ) > is actually operating on the type of a function that returns Func_Type and takes (Args...). It then says "what if we applied Args... to Func_Type. This fails to work when Func_Type is an actual type of a function, because you aren't allowed to return actual instances of functions.
std::decay turns Func_Type as the type of a function into a pointer to the same type of function, which is something a function can return. And you can invoke a pointer to a function just like you invoke an actual function, so no harm there either.