Related
I don't know if there is a good and clean way to index variadic arguments when unpacking tuple-like objects into callable handlers, i.e. when using std::apply.
Here is a not perfect, but rather clean solution:
const auto animals = std::make_tuple("cow", "dog", "sheep");
// handwritten, stateful, bad...
std::apply([](const auto& ... str){
const auto print = [](const auto& str, size_t index){
std::cout << index << ": " << str << '\n';
};
// this should not be done by the user!!!
size_t i = 0;
(print(str, i++), ...);
}, animals);
This solution is cleaner than using overloads with std::index_sequence since you don't have to write any code outside lambda's scope. Templates are not allowed within a block scope, so one would need to create some helper class outside.
It is bad, since there is a mutable state that is created by user. There should be no such thing, index should be available implicitly and on demand.
Here is what I think is desired and what I managed to implement so far:
const auto animals = std::make_tuple("cow", "dog", "sheep");
// desired
// JavaScript-style destructuring.
// C++ structured bindings are not allowed as arguments
// apply([](auto ... {value, index}){ ... }, animals);
// still bad, but better - index is implicit and constant
std::apply(indexed([](auto ... indexedValue){
const auto print = [](const auto& indexedValue){
const auto &[index, value] = indexedValue;
std::cout << index << ": " << value << '\n';
};
(print(indexedValue), ...);
}), animals);
C++ does not allow to have structured bindings as function arguments, and this is very unfortunate. Anyways, I consider this api better, than incrementing a counter by hand or writing some boilerplate helper.
All you have to do is to follow the damn train wrap your callable into indexed() function.
And it does not require any modifications on STL's part.
However, my implementation is very far from optimal. It results in far more instructions than the first example: https://godbolt.org/z/3G4doao39
Here is my implementation for indexed() function which I would like to be corrected.
#include <cstddef>
#include <type_traits>
#include <tuple>
namespace detail {
template <size_t I, typename T>
struct _indexed
{
constexpr static size_t index = I;
T value;
constexpr _indexed(std::integral_constant<size_t, I>, T t)
: value(t)
{}
template <size_t Elem>
friend constexpr auto get(const detail::_indexed<I, T>& v) noexcept ->
std::tuple_element_t<Elem, detail::_indexed<I, T>>{
if constexpr (Elem == 0)
return I;
if constexpr (Elem == 1)
return v.value;
}
};
template <size_t I, typename T>
_indexed(std::integral_constant<size_t, I>, T) -> _indexed<I, T>;
template <typename CRTP>
class _add_indices
{
public:
template <typename ... Args>
constexpr decltype(auto) operator()(Args &&... args) const noexcept {
return (*this)(std::make_index_sequence<sizeof...(Args)>(), std::forward<Args>(args)...);
}
private:
template <typename ... Args, size_t ... I>
constexpr decltype(auto) operator()(std::index_sequence<I...>, Args ... args) const noexcept {
// does not compile
// return std::invoke(&CRTP::callable, static_cast<CRTP const&>(*this),
// _indexed(std::integral_constant<size_t, I>{}, std::forward<Args>(args))...);
return static_cast<const CRTP&>(*this).callable(_indexed(std::integral_constant<size_t, I>{}, std::forward<Args>(args))...);
}
};
}
template <size_t I, typename T>
struct std::tuple_size<detail::_indexed<I, T>> : std::integral_constant<size_t, 2> {};
template <size_t I, typename T>
struct std::tuple_element<0, detail::_indexed<I, T>>
{
using type = size_t;
};
template <size_t I, typename T>
struct std::tuple_element<1, detail::_indexed<I, T>>
{
using type = T;
};
template <typename Callable>
constexpr auto indexed(Callable c) noexcept{
struct _c : detail::_add_indices<_c> {
Callable callable;
};
return _c{.callable = c};
}
// api:
// apply(indexed([](auto ... indexedValue){}), tuple);
If I correctly understand what do you want... it seems to me that you only need a class/struct as follows
template <typename Callable>
struct indexed_call
{
Callable c;
template <std::size_t ... Is, typename ... As>
constexpr auto call (std::index_sequence<Is...>, As && ... as) const {
return c(std::pair{Is, std::forward<As>(as)}...);
}
template <typename ... As>
constexpr auto operator() (As && ... as) const {
return call(std::index_sequence_for<As...>{}, std::forward<As>(as)...);
}
};
and an explicit, trivial, deduction guide
template <typename C>
indexed_call(C) -> indexed_call<C>;
and the call change a little as follows
std::apply(indexed_call{[](auto ... indexedValue){
const auto print = [](const auto& iV){
const auto &[index, value] = iV;
std::cout << index << ": " << value << '\n';
};
(print(indexedValue), ...);
}}, animals);
or, if you prefer, also the call can be simplified
std::apply(indexed_call{[](auto ... iV){
((std::cout << iV.first << ": " << iV.second << '\n'), ...);
}}, animals);
The following is a full compiling example
#include <type_traits>
#include <iostream>
#include <tuple>
template <typename Callable>
struct indexed_call
{
Callable c;
template <std::size_t ... Is, typename ... As>
constexpr auto call (std::index_sequence<Is...>, As && ... as) const {
return c(std::pair{Is, std::forward<As>(as)}...);
}
template <typename ... As>
constexpr auto operator() (As && ... as) const {
return call(std::index_sequence_for<As...>{}, std::forward<As>(as)...);
}
};
template <typename C>
indexed_call(C) -> indexed_call<C>;
int main(){
const auto animals = std::make_tuple("cow", "dog", "sheep");
std::apply(indexed_call{[](auto ... indexedValue){
const auto print = [](const auto& iV){
const auto &[index, value] = iV;
std::cout << index << ": " << value << '\n';
};
(print(indexedValue), ...);
}}, animals);
std::apply(indexed_call{[](auto ... iV){
((std::cout << iV.first << ": " << iV.second << '\n'), ...);
}}, animals);
}
----- EDIT -----
The OP writes
I don't think that utilizing std::pair is semantically correct. Would be better to have .value, .index
I usually prefer to use standard components, when functional equivalents, but if you want something with a value and a index components, you can add a simple struct (name it as you prefer)
template <typename V>
struct val_with_index
{
std::size_t index;
V value;
};
and another trivial explicit deduction guide
template <typename V>
val_with_index(std::size_t, V) -> val_with_index<V>;
then you have to modify the call() method to use it instead std::pair
template <std::size_t ... Is, typename ... As>
constexpr auto call (std::index_sequence<Is...>, As && ... as) const {
return c(val_with_index{Is, std::forward<As>(as)}...);
} // ......^^^^^^^^^^^^^^
and now works for the double lambda case
For the simplified case, obviously you have to change first and second with index and value
std::apply(indexed_call{[](auto ... iV){
((std::cout << iV.index << ": " << iV.value << '\n'), ...);
}}, animals); // ....^^^^^...............^^^^^
Again the full compiling example
#include <type_traits>
#include <iostream>
#include <tuple>
template <typename V>
struct val_with_index
{
std::size_t index;
V value;
};
template <typename V>
val_with_index(std::size_t, V) -> val_with_index<V>;
template <typename Callable>
struct indexed_call
{
Callable c;
template <std::size_t ... Is, typename ... As>
constexpr auto call (std::index_sequence<Is...>, As && ... as) const {
return c(val_with_index{Is, std::forward<As>(as)}...);
}
template <typename ... As>
constexpr auto operator() (As && ... as) const {
return call(std::index_sequence_for<As...>{}, std::forward<As>(as)...);
}
};
template <typename C>
indexed_call(C) -> indexed_call<C>;
int main(){
const auto animals = std::make_tuple("cow", "dog", "sheep");
std::apply(indexed_call{[](auto ... indexedValue){
const auto print = [](const auto& iV){
const auto &[index, value] = iV;
std::cout << index << ": " << value << '\n';
};
(print(indexedValue), ...);
}}, animals);
std::apply(indexed_call{[](auto ... iV){
((std::cout << iV.index << ": " << iV.value << '\n'), ...);
}}, animals);
}
I am trying to implement a recursive version std::invoke_result_t with C++20 concept so that the type of nested invoke result can be retrieved.
The use case of recursive_invoke_result_t
auto f1 = [](int x) { return static_cast<double>(x); };
std::cout << typeid(recursive_invoke_result_t<decltype(f1), int>).name() << std::endl; // expected output "double"
std::cout << typeid(recursive_invoke_result_t<decltype(f1), std::vector<int>>).name() << std::endl; // expected output is something like "std::vector<double>"
std::cout << typeid(recursive_invoke_result_t<decltype(f1), std::vector<std::vector<int>>>).name() << std::endl; // expected output is something like "std::vector<std::vector<double>>"
auto f2 = [](int x) { return std::to_string(x); };
std::cout << typeid(recursive_invoke_result_t<decltype(f2), std::vector<int>>).name() << std::endl; // expected output is something like "std::vector<string>"
auto f3 = [](std::string x) { return std::atoi(x.c_str()); };
std::cout << typeid(recursive_invoke_result_t<decltype(f3), std::vector<std::string>>).name() << std::endl; // expected output is something like "std::vector<int>"
The experimental implementation
The experimental implementation is as below.
// recursive_invoke_result_t implementation
template<typename F, typename T>
requires (std::invocable<F, T>)
struct recursive_invoke_result_t_detail
{
using type = std::invoke_result_t<F, T>;
};
template <typename F, template <typename...> typename Container, typename... Ts>
requires (std::ranges::input_range<std::ranges::range_value_t<Container<Ts...>>>) && (!std::invocable<F, Container<Ts...>>)
struct recursive_invoke_result_t_detail<F, Container<Ts...>>
{
using type = Container<typename recursive_invoke_result_t_detail<F, std::iter_value_t<Container<Ts...>>>::type>;
};
template<typename F, typename T>
using recursive_invoke_result_t = typename recursive_invoke_result_t_detail<F, T>::type;
In the above experimental implementation, the test case recursive_invoke_result_t<decltype(f1), int> seems to be working fine. When it comes to the second test case recursive_invoke_result_t<decltype(f1), std::vector<int>>, the compile errors 'recursive_invoke_result_t_detail': the associated constraints are not satisfied, 'recursive_invoke_result_t' : Failed to specialize alias template and unable to recover from previous error(s); stopping compilation occurred. Is there any way to solve this? Please give me some hints or examples.
This
template<typename F, typename T> requires std::invocable<F, T>
struct recursive_invoke_result_t_detail
{
using type = std::invoke_result_t<F, T>;
};
is the primary template for recursive_invoke_result_t_detail. The requires std::invocable<F, T> then means that recursive_invoke_result_t_detail<F, T> is only valid if std::invocable<F, T>. Period. No specialization can relax this requirement; it is a property of the template itself. The requires constraint on the specialization is just an added constraint: the template can only be instantiated with <F, T> if std::invocable<F, T>, and that partial specialization only applies if, further, T = Container<Ts...> for some Ts... and the other constraint you gave is satisfied (which is actually impossible!)
Leave the primary template unconstrained (and also name and alias it according to convention)
template<typename, typename>
struct recursive_invoke_result { };
template<typename F, typename T>
using recursive_invoke_result_t = recursive_invoke_result<F, T>::type;
Give a partial specialization for the base case
template<typename T, std::invocable<T> F>
struct recursive_invoke_result<F, T> { using type = std::invoke_result_t<F, T>; };
and then your other partial specialization
template<typename F, template<typename...> typename Container, typename... Ts>
requires (
!std::invocable<F, Container<Ts...>> && // don't conflict with base case
std::ranges::input_range<Container<Ts...>> && // no idea why you asked for the contained type to be range, fixed it
requires { typename recursive_invoke_result_t<F, std::ranges::range_value_t<Container<Ts...>>>; }) // SFINAE-compatibility
struct recursive_invoke_result<F, Container<Ts...>> {
using type = Container<recursive_invoke_result_t<F, std::ranges::range_value_t<Container<Ts...>>>>; // not iter_value_t, the container isn't an iterator!
};
Yum.
// typeid(...).name() doesn't produce anything readable for me on Godbolt
template<typename T>
std::ostream &print_type(std::ostream &out) {
// stealing https://stackoverflow.com/a/20170989
// works only for GCC
std::string_view name = __PRETTY_FUNCTION__;
name.remove_prefix(50);
name.remove_suffix(42);
return out << name;
};
template<typename T>
constexpr void assert_no_type() { }
template<typename T> requires requires { typename T::type; }
void assert_no_type() = delete;
int main() {
using F = decltype([](int x) -> double { return x; });
std::cout << "double(int), int: " << print_type<recursive_invoke_result_t<F, int>> << "\n";
std::cout << "double(int), std::vector<int>: " << print_type<recursive_invoke_result_t<F, std::vector<int>>> << "\n";
assert_no_type<recursive_invoke_result<F, std::vector<std::ostream>>>();
std::cout << "double(int), std::vector<std::vector<int>>: " << print_type<recursive_invoke_result_t<F, std::vector<std::vector<int>>>> << "\n";
std::cout << "double(int), std::vector<std::set<int>>: " << print_type<recursive_invoke_result_t<F, std::vector<std::set<int>>>> << "\n";
using G = decltype([](std::vector<int> const &v) -> std::vector<double> { return {}; });
assert_no_type<recursive_invoke_result<G, std::set<std::set<int>>>>();
std::cout << "std::vector<double>(std::vector<int>): " << print_type<recursive_invoke_result_t<G, std::set<std::vector<int>>>> << "\n";
}
Godbolt
Suppose we have this template
template<typename Container, typename T>
bool contains (const Container & theContainer, const T & theReference) {
...
}
How can it be stated that, obviously the elements in container should be of type T?
Can this all be abbreviated (maybe in C++11)?
While other answers using value_type are correct , the canonical solution to this frequent problem is to not pass the container in the first place : use the Standard Library semantics, and pass a pair of iterators.
By passing iterators, you don't have to worry about the container itself. Your code is also much more generic : you can act on ranges, you can use reversed iterators, you can combine your template with other standard algorithms etc.. :
template<typename Iterator, typename T>
bool contains (Iterator begin, Iterator end, const T& value) {
...
}
int main(){
std::vector<int> v { 41, 42 };
contains(std::begin(v), std::end(v), 42);
};
If you want to check the type carried by Iterator, you can use std::iterator_traits :
static_assert(std::is_same<typename std::iterator_traits<Iterator>::value_type, T>::value, "Wrong Type");
(Note that this assertion is generally not needed : if you provide a value not comparable with T, the template will not compile in the first place)
The final template would look like :
template<typename Iterator, typename T>
bool contains (Iterator begin, Iterator end, const T& value) {
static_assert(std::is_same<typename std::iterator_traits<Iterator>::value_type, T>::value, "Wrong Type");
while(begin != end)
if(*begin++ == value)
return true;
return false;
}
Live demo
Notes:
1) This should not be a surprise, but our contains template now has almost the same signature than std::find (which returns an iterator) :
template< class InputIt, class T >
InputIt find( InputIt first, InputIt last, const T& value );
2) If modifying the signature of the original contains is too much, you can always forward the call to our new template :
template<typename Container, typename T>
bool contains (const Container & theContainer, const T & theReference) {
return contains(std::begin(theContainer), std::end(theContainer), theReference);
}
You might restrict the container type in the template:
#include <algorithm>
#include <iostream>
#include <vector>
template< template<typename ... > class Container, typename T>
bool contains(const Container<T>& container, const T& value) {
return std::find(container.begin(), container.end(), value) != container.end();
}
int main()
{
std::vector<int> v = { 1, 2, 3 };
std::cout << std::boolalpha
<< contains(v, 0) << '\n'
<< contains(v, 1) << '\n';
// error: no matching function for call to ‘contains(std::vector<int>&, char)’
contains(v, '0') ;
return 0;
}
A more complete solution (addressing some comments):
#include <algorithm>
#include <array>
#include <iostream>
#include <map>
#include <set>
#include <vector>
// has_member
// ==========
namespace Detail {
template <typename Test>
struct has_member
{
template<typename Class>
static typename Test::template result<Class>
test(int);
template<typename Class>
static std::false_type
test(...);
};
}
template <typename Test, typename Class>
using has_member = decltype(Detail::has_member<Test>::template test<Class>(0));
// has_find
// ========
namespace Detail
{
template <typename ...Args>
struct has_find
{
template<
typename Class,
typename R = decltype(std::declval<Class>().find(std::declval<Args>()... ))>
struct result
: std::true_type
{
typedef R type;
};
};
}
template <typename Class, typename ...Args>
using has_find = has_member<Detail::has_find<Args...>, Class>;
// contains
// ========
namespace Detail
{
template<template<typename ...> class Container, typename Key, typename ... Args>
bool contains(std::false_type, const Container<Key, Args...>& container, const Key& value) {
bool result = std::find(container.begin(), container.end(), value) != container.end();
std::cout << "Algorithm: " << result << '\n';;
return result;
}
template<template<typename ...> class Container, typename Key, typename ... Args>
bool contains(std::true_type, const Container<Key, Args...>& container, const Key& value) {
bool result = container.find(value) != container.end();
std::cout << " Member: " << result << '\n';
return result;
}
}
template<template<typename ...> class Container, typename Key, typename ... Args>
bool contains(const Container<Key, Args...>& container, const Key& value) {
return Detail::contains(has_find<Container<Key, Args...>, Key>(), container, value);
}
template<typename T, std::size_t N>
bool contains(const std::array<T, N>& array, const T& value) {
bool result = std::find(array.begin(), array.end(), value) != array.end();
std::cout << " Array: " << result << '\n';;
return result;
}
// test
// ====
int main()
{
std::cout << std::boolalpha;
std::array<int, 3> a = { 1, 2, 3 };
contains(a, 0);
contains(a, 1);
std::vector<int> v = { 1, 2, 3 };
contains(v, 0);
contains(v, 1);
std::set<int> s = { 1, 2, 3 };
contains(s, 0);
contains(s, 1);
std::map<int, int> m = { { 1, 1}, { 2, 2}, { 3, 3} };
contains(m, 0);
contains(m, 1);
return 0;
}
For standard container, you may use value_type:
template<typename Container>
bool contains (const Container & theContainer, const typename Container::value_type& theReference) {
...
}
Note that there is also const_reference in your case:
template<typename Container>
bool contains (const Container & theContainer, typename Container::const_reference theReference) {
...
}
You can check the value_type of container and T using static_assert
template<typename Container, typename T>
bool contains (const Container & theContainer, const T & theReference) {
static_assert( std::is_same<typename Container::value_type, T>::value,
"Invalid container or type" );
// ...
}
Demo Here
Using std::enable_if (http://en.cppreference.com/w/cpp/types/enable_if), but a little more complicated than with static_assert.
EDIT: According to P0W's comment, using std::enable_if allows us to use SFINAE, which is nice when you decide to have more overloads. For example if the compiler decides to use this templated function, with a Container with no value_type typedefed, it won't generate an error instantly, like static_assert would, just looks for other functions which perfectly fits the signature.
Tested on Visual Studio 12.
#include <vector>
#include <iostream>
template<typename Container, typename T>
typename std::enable_if<
std::is_same<T, typename Container::value_type>::value, bool>::type //returns bool
contains(const Container & theContainer, const T & theReference)
{
return (std::find(theContainer.begin(), theContainer.end(), theReference) != theContainer.end());
};
int main()
{
std::vector<int> vec1 { 1, 3 };
int i = 1;
float f = 1.0f;
std::cout << contains(vec1, i) << "\n";
//std::cout << contains(vec1, f); //error
i = 2;
std::cout << contains(vec1, i) << "\n";
};
output:
1
0
PS: Your original function does it too, except that allows derived classes too. These solutions does not.
I'm looking for a way to pass function pointers, functors or lambdas to a template function g which uses the passed function's argument types, for example:
template<class T1, class T2, class T3>
struct wrapper_t {
boost::function<void(T1,T2,T3)> f;
wrapper_t( boost::function<void(T1,T2,T3)> f ) : f(f) {}
void operator( std::vector<T1> &a, std::vector<T2> &b, T3 c ) {
assert(a.size() == b.size());
for(size_t i = 0 ; i != a.size() ; i++) f(a[i], b[i], c);
}
};
template<class T1, class T2, class T3>
wrapper_t<T1,T2,T3> make_wrapper( boost::function<void(T1,T2,T3)> f ) {
return wrapper_t<T1,T2,T3>( f );
}
void f(int, double, char) {};
wrapper_t<int, double, char> w0(f); // need to repeat types
auto w1 = make_wrapper(f); // more comfortable
std::vector<int> a{{1, 2, 3}};
std::vector<double> b{{1.0, 2.0, 3.0}};
w0( a, b, 'c' );
w1( a, b, 'c' );
The make_wrapper function only exists to extract the types from the argument, some syntactic sugar to avoid having to type them twice.
A minimal example for my problem is this function:
template<class T>
void g1( const boost::function<void(T)> & ) {}
Using these as input
void f1(int) {}
struct f2_t { void operator()(int) {} };
it fails to infer T=int
f2_t f2;
g1( f1 ); // mismatched types ‘const std::function<void(T)>’ and ‘void(int)’
g1( f2 ); // ‘f2_t’ is not derived from ‘const std::function<void(T)>’
g1( [](int){} ); // ‘::<lambda(int)>’ is not derived from ‘…
g1<int>( f1 ); // ok
g1<int>( f2 ); // ok
g1<int>( [](int){} ); // ok
But T=int can be inferred from a plain function pointer, but of this doesn't work with the functor or lambda either:
template<class T>
void g2( void (*)(T) ) {}
g2( f1 ); // ok
g2( f2 ); // mismatched types …
g2<int>( f2 ); // ok
g2( [](int){} ); // mismatched types …
g2<int>( [](int){} ); // ok
Is there a way to infer T not just for plain function pointers but for functors and lambdas, too?
Or does it have to be something like this?
template<class F>
void g( F ) { typedef first_argument_of<F>::type T; }
(in my real code I need to deconstruct a function with four arguments this way, but std::function::…argument_type only exists for one or two arguments; boost::function has argN_type, but I don't think I can use that anyway since F is not always a function which is my problem, see above, etc)
There is no way to do what you want for a variety of reasons. But here is one that should make the problem pretty clear:
struct function_object
{
template<typename ...T>
void operator ()(T&&... v){}
};
f( function_object{} );
What is the type of the arguments of the function object passed to f? There isn't any, it can be called with any kind and number of arguments.
I also think there is no direct way to define the template parameters and function arguments of a single, primary template definition such that T can be deduced in all the different situations (function pointer, lambda expression, std::function argument etc.).
I would therefore recommend that you follow the approach suggested at the end of your question. Indeed neither std::function nor the tools offered by Boost (as far as I know) will easily enable this, though.
What I use (and I learnt that from other SO posts in the past), is a rather complicated template function_traits with specializations for all the different cases. My definition is this:
template <typename T>
struct function_traits
: public function_traits<decltype(&T::operator())>
{ };
template <typename Return, typename... Args>
struct function_traits<Return(Args...)>
{
typedef std::size_t size_type;
typedef Return result_type;
typedef result_type function_type(Args...);
static constexpr size_type arity = sizeof...(Args);
template <size_type index>
struct arg
{
typedef typename std::tuple_element<index,std::tuple<Args...>>::type type;
};
static constexpr bool value = true;
};
template <typename Return, typename... Args>
struct function_traits<Return(*)(Args...)>
: function_traits<Return(Args...)>
{ };
template <typename Return, typename... Args>
struct function_traits<Return(&)(Args...)>
: function_traits<Return(Args...)>
{ };
template <typename Class, typename Return, typename... Args>
struct function_traits<Return(Class::*)(Args...)>
: function_traits<Return(Args...)>
{ };
template <typename Class, typename Return, typename... Args>
struct function_traits<Return(Class::*)(Args...) volatile>
: function_traits<Return(Args...)>
{ };
template <typename Class, typename Return, typename... Args>
struct function_traits<Return(Class::*)(Args...) const>
: function_traits<Return(Args...)>
{ };
template <typename Class, typename Return, typename... Args>
struct function_traits<Return(Class::*)(Args...) const volatile>
: function_traits<Return(Args...)>
{ };
To make using this even more convenient, you may want to define using-aliases:
template <typename Fun>
using result_of = typename function_traits<Fun>::result_type;
template <typename Fun, std::size_t index>
using arg = typename function_traits<Fun>::template arg<index>::type;
With all these definitions (which in the below, I assume you put into a separate header more_type_traits.hpp), you can then easily define your wrapper function as follows:
#include <iostream>
#include <functional>
#include <type_traits>
#include "more_type_traits.hpp"
template <typename Fun>
using noref = typename std::remove_reference<Fun>::type;
template <typename Fun>
result_of<noref<Fun>> fun(Fun &&argfun)
{
// Default-initialize the first argument
arg<noref<Fun>,0> arg {};
// Call the function
return argfun(arg);
}
The below (which is basically copied from your code) then compiles and works for me:
void f1(int i)
{ std::cout << "f1(" << i << ')' << std::endl; }
struct f2_t
{
void operator()(int i)
{ std::cout << "f2(" << i << ')' << std::endl; }
};
int main()
{
fun(f1);
f2_t f2;
fun(f2);
std::function<void(int)> funobj = [](int i)
{ std::cout << "funobj(" << i << ')' << std::endl; };
fun(funobj);
fun( [](int i) { std::cout << "lambda(" << i << ')' << std::endl; } );
return 0;
}
Clearly, the definition of function_traits is complicated, because many different specializations are required. But it's worth the effort if you want to make function wrapping convenient.
Lets suppose I read in a comment that the OP really wants to take a function that mutates a T, and turn it into a function that mutates a std::vector<T>, and thinks that in order to do this you need to know what T is.
You don't
#include <type_traits>
#include <utility>
template<typename Lambda>
struct container_version {
Lambda closure;
container_version( container_version const& ) = default;
container_version( container_version && ) = default;
container_version( container_version & ) = default;
template<typename U>
container_version( U&& func ):closure(std::forward<U>(func)) {};
// lets make this work on any iterable range:
template<typename Container>
void operator()( Container&& c ) const {
for( auto&& x:c )
closure(x);
}
};
template<typename Lambda>
container_version< typename std::decay<Lambda>::type >
make_container_version( Lambda&& closure ) {
return {std::forward<Lambda>(closure)};
}
#include <vector>
#include <iostream>
#include <functional>
#include <array>
int main() {
std::vector<int> my_vec = {0, 1, 2, 3};
for (auto x:my_vec)
std::cout << x << ",";
std::cout << "\n";
make_container_version( []( int& x ) { x++; })( my_vec );
for (auto x:my_vec)
std::cout << x << ",";
std::cout << "\n";
// hey look, we can store it in a `std::function` if we need to:
auto super_func = make_container_version( []( int& x ) { x++; } );
std::function< void( std::vector<int>& ) > func = super_func;
// and the same super_func can be used for a function on a different container:
std::function< void( std::array<int,7>& ) > func2 = super_func;
func(my_vec);
for (auto x:my_vec)
std::cout << x << ",";
std::cout << "\n";
}
In fact, taking the argument and turning it into a std::function, or forcing it to be stored in a std::function, costs efficiency, increases the complexity of the code, and makes it unable to do things that it has no problem doing.
The above version, before it is packed into a std::function, can operate on sets, lists, vectors , raw C arrays, std::arrays, etc.
Suppose I have a std::tuple made up of types like
struct A {
static void tip();
};
struct B {
static void tip();
};
struct Z {
};
std::tuple<const A&,const B&,const Z&> tpl;
Yes, I need separate A, B. (The implementation of ::tip() differs for each type.) What I try to implement is a type-sensitive "visitor" that iterates through the tuple starting from the beginning to the end. Upon visiting a particular element of type T a function should be called depending on whether T has the ::tip() method or not. In the simple example of above only A and B have ::tip() implemented and Z not. So, the iterator should call twice the function for types with the ::tip() method and once the other function.
Here is what I came up with:
template< int N , bool end >
struct TupleIter
{
template< typename T , typename... Ts >
typename std::enable_if< std::is_function< typename T::tip >::value , void >::type
static Iter( const T& dummy , const std::tuple<Ts...>& tpl ) {
std::cout << "tip\n";
std::get<N>(tpl); // do the work
TupleIter<N+1,sizeof...(Ts) == N+1>::Iter( std::get<N+1>(tpl) , tpl );
}
template< typename T , typename... Ts >
typename std::enable_if< ! std::is_function< typename T::tip >::value , void >::type
static Iter( const T& dummy , const std::tuple<Ts...>& tpl ) {
std::cout << "no tip\n";
std::get<N>(tpl); // do the work
TupleIter<N+1,sizeof...(Ts) == N+1>::Iter( std::get<N+1>(tpl) , tpl );
}
};
template< int N >
struct TupleIter<N,true>
{
template< typename T , typename... Ts >
static void Iter( const std::tuple<Ts...>& tpl ) {
std::cout << "end\n";
}
};
I use a dummy instance of the type of the element at the iterator position and decide via enable_if which function to call. Unfortunately this doesn't work/isn't a nice solution:
The compiler complains about recursive instantiation
The const T& dummy is not a clean solution
I was wondering if enable_if is the right strategy to do the decision and how can one recursively iterate through the std::tuple capturing the first type and keeping all the remaining arguments in vital state. Read through How to split a tuple? but it doesn't do any decision.
How can one implement such a thing in a correct and portable way in C++11?
Well, it was harder than I expected, but this works.
Some things you were doing wrong/that I modified:
You can't evaluate this: std::is_function< typename T::tip >::value, since T::tip is not a type. Even if this could be evaluated, what would happen when T::tip does not exist? Substitution would still fail.
Since you use const references as your tuple's inner types, you had to clean them before trying to find the tip member inside them. By cleaning I mean removing const and removing the reference.
That dummy type stuff was not a good idea, there was no need to use that parameter. You can achieve the same thing using std::tuple_element, which retrieves the i-th type from a tuple.
I modified TupleIter's template parameters to the following, which means:
"TupleIter that processes the index-th type, inside a tuple of size n".
template<size_t index, size_t n>
struct TupleIter;
The whole code is this:
#include <tuple>
#include <iostream>
#include <type_traits>
struct A {
static void tip();
};
struct B {
static void tip();
};
struct Z {
};
// Indicates whether the template parameter contains a static member named tip.
template<class T>
struct has_tip {
template<class U>
static char test(decltype(&U::tip));
template<class U>
static float test(...);
static const bool value = sizeof(test<typename std::decay<T>::type>(0)) == sizeof(char);
};
// Indicates whether the n-th type contains a tip static member
template<size_t n, typename... Ts>
struct nth_type_has_tip {
static const bool value = has_tip<typename std::tuple_element<n, std::tuple<Ts...>>::type>::value;
};
// Generic iteration
template<size_t index, size_t n>
struct TupleIter
{
template< typename... Ts >
typename std::enable_if< nth_type_has_tip<index, Ts...>::value , void >::type
static Iter(const std::tuple<Ts...>& tpl)
{
std::cout << "tip\n";
TupleIter<index + 1, n>::Iter(tpl );
}
template< typename... Ts >
typename std::enable_if< !nth_type_has_tip<index, Ts...>::value , void >::type
static Iter(const std::tuple<Ts...>& tpl) {
std::cout << "no tip\n";
TupleIter<index + 1, n>::Iter(tpl );
}
};
// Base class, we've reached the tuple end
template<size_t n>
struct TupleIter<n, n>
{
template<typename... Ts >
static void Iter( const std::tuple<Ts...>& tpl ) {
std::cout << "end\n";
}
};
// Helper function that forwards the first call to TupleIter<>::Iter
template<typename... Ts>
void iterate(const std::tuple<Ts...> &tup) {
TupleIter<0, sizeof...(Ts)>::Iter(tup);
}
int main() {
A a;
B b;
Z z;
std::tuple<const A&,const B&,const Z&> tup(a,b,z);
iterate(tup);
}
Here is another take on the question, very similar to mfontanini answer, but showcasing:
boost::fusion::for_each (instead of manually iterate over the tuple).
A variant for implementing has_type using an expression-based SFINAE approach, that I feel a little bit simpler to follow than the usual sizeof trick.
#include <boost/tuple/tuple.hpp>
#include <boost/fusion/include/boost_tuple.hpp>
#include <boost/fusion/algorithm.hpp>
#include <iostream>
struct nat // not a type
{
private:
nat();
nat(const nat&);
nat& operator=(const nat&);
~nat();
};
template <typename T>
struct has_tip
{
static auto has_tip_imp(...) -> nat;
template <typename U>
static auto has_tip_imp(U&&) -> decltype(U::tip());
typedef decltype(has_tip_imp(std::declval<T>())) type;
static const bool value = !std::is_same<type, nat>::value;
};
struct CallTip
{
template<typename T>
typename std::enable_if<has_tip<T>::value>::type
operator()(T& t) const
{
std::cout << "tip\n";
T::tip();
}
template<typename T>
typename std::enable_if<!has_tip<T>::value>::type
operator()(T& t) const
{
std::cout << "no tip\n";
return;
}
};
struct A {
static void tip(){}
};
struct B {
static void tip(){}
};
struct Z {
};
int main()
{
A a;
B b;
Z z;
boost::tuple<const A&,const B&,const Z&> tpl(a, b, z);
boost::fusion::for_each(tpl, CallTip());
}
Note that if your compiler support variadic template you can use std::tuple instead of boost::tuple inside fusion::for_each by including #include<boost/fusion/adapted/std_tuple.hpp>
Edit :
As pointed by Xeo in the comment, it is possible to simplify a lot the expression-SFINAE approach by removing completely the trait has_tip and simply forward to a little call helper.
The final code is really neat and tight !
#include <boost/tuple/tuple.hpp>
#include <boost/fusion/include/boost_tuple.hpp>
#include <boost/fusion/algorithm.hpp>
#include <iostream>
struct CallTip
{
template<typename T>
void operator()(const T& t) const
{
call(t);
}
template<class T>
static auto call(const T&) -> decltype(T::tip())
{
std::cout << "tip\n";
T::tip();
}
static void call(...)
{
std::cout << "no tip\n";
}
};
struct A {
static void tip(){}
};
struct B {
static void tip(){}
};
struct Z {
};
int main()
{
A a;
B b;
Z z;
boost::tuple<const A&,const B&,const Z&> tpl(a, b, z);
boost::fusion::for_each(tpl, CallTip());
}