Getting rid of references in an boost::fusion sequence - c++

I'm trying to use Boost::Fusion to transform a list of function's parameter types into a fusion::list. Ultimately, I am trying to turn a list of variables into parameters that I can call a function with (http://stackoverflow.com/questions/11164914/generating-wrappings-for-c-functions).
I've gotten this to work for non-referenced variables. However, it fails to compile for non-referenced variables when I try to turn the function's parameter list (specifically on the fusion::to_list it complains it can't deref the iterator).
I've simplified the code down by a bit below:
struct identity {
template<typename Sig> struct result;
template <typename T>
struct result<convert(T)> { typedef T type; };
template <typename T>
typename T operator ()(T) const {
return T();
}
};
int main(int argc, char **argv) {
typedef BOOST_TYPEOF(foo) params_type;
auto seq = function_types::parameter_types<params_type>();
auto transformed = fusion::transform(seq, identity());
auto passedParams = fusion::as_list(transformed);
}
If foo is defined as:
int foo(int a) { return 5*a; }
it works fine, but it breaks on:
int foo(int &a) { return 5*a; }
For the purposes of my code, I don't actually need the references kept in the sequence, which I am assuming is the issue (also, searches I've done tend to point that as being the culprit). However, I'm not completely sure of how to strip the transformed function of these references before as_list is called.
I tried something along the lines of:
template <typename T>
struct result<convert(T)>: remove_reference<T> {};
template <typename T>
typename remove_reference<T>::type operator ()(remove_reference<T>::type) const { return typename remove_reference<T>::type(); }
but got the same compile errors.
Any ideas of how to fix this?
update
Here is the truncated compiler error I get (with clang++ --std=c++0x) for both cases given above:
/usr/local/include/boost/fusion/adapted/mpl/mpl_iterator.hpp:43:24: error:
reference to type 'int' requires an initializer
return type();
^
/usr/local/include/boost/fusion/iterator/deref.hpp:61:28: note: in instantiation
of member function
'boost::fusion::mpl_iterator<boost::mpl::v_iter<boost::function_types::parameter_types<void
(int &), boost::add_reference<mpl_::arg<-1> > >, 0>
>::deref<boost::fusion::mpl_iterator<boost::mpl::v_iter<boost::function_types::parameter_types<void
(int &), boost::add_reference<mpl_::arg<-1> > >, 0> > >::call' requested
here
return deref_meta::call(i);
...
test4.cpp:65:22: note: in instantiation of function template specialization
'boost::fusion::as_list<boost::fusion::transform_view<const
boost::function_types::parameter_types<void (int &),
boost::add_reference<mpl_::arg<-1> > >, convert, boost::fusion::void_> >'
requested here
auto passedParams = fusion::as_list(transformed);

If your compiler is C++11 compatible, you might want to look into the `std::remove_reference function. Or at least try to find an implementation of it and use as reference for making your own.

Related

partial specialisation and nested templates

I try to do partial specialisation for a template function where the specialized type T might also be a class template. However the following Code does not work.
#include <iostream>
#include <vector>
template <class T>
constexpr T neutral();
template <>
constexpr int neutral() { return 0; } // Okay. This is how partial specialisation works.
template <class U>
constexpr std::vector<U> neutral() { return std::vector<U>{ neutral<U>() }; }
int main()
{
const auto n{ neutral<std::vector<int>>() }; // error
}
main.cpp:16:19: error: call to 'neutral' is ambiguous
const auto n{ neutral<std::vector<int>>() }; // error
^~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:5:13: note: candidate function [with T = std::vector<int, std::allocator<int> >]
constexpr T neutral();
^
main.cpp:11:26: note: candidate function [with U = std::vector<int, std::allocator<int> >]
constexpr std::vector<U> neutral() { return std::vector<U>{ neutral<U>() }; } //error
^
My design goal is as follows: I provide an algorithm that can take any type that any programmer wants to use as long as he defines what the so called natural<T>() of his type T is. (However my actual code looks differently. This is a minimalistic example I tried to extract.)
How can it be implemented correctly?
I first thought, it must be something like
template <>
template <class U>
constexpr std::vector<U> neutral<std::vector<U>>() { return std::vector<U>{ neutral<U>() }; } //error
But this also ends up in errors:
main.cpp:11:26: error: function template partial specialization is not allowed
constexpr std::vector<U> neutral<std::vector<U>>() { return std::vector<U>{ neutral<U>() }; } //error
^ ~~~~~~~~~~~~~~~~
EDIT:
The context I want to use it is like this...
I have some class class Z7 which is representing a (math.) ring. I want to use something like the neutral in the example for the zero and the one element of the ring. Then there is a class
template <class _Ring>
class polynomial;
which will represent polynoms over the ring _Ring, e.g., 2x^5 + x^3 + 4x + 1. Therefore, polynomial<_Ring> will also be a ring whenever _Ring has been a ring. Thus I want to define a template specialisation for a zero and a one for polynomial<_Ring> by using the zero and one of type _Ring.
Functions need a difference in their parameters to have different definitions, classes/structs can be specialized without such a constraint, perhaps what you're looking for is closer to...
#include <vector>
template <typename T>
struct neutral;
template <typename T>
struct neutral {
static constexpr int get() { return 0; }
};
template <typename T>
struct neutral<std::vector<T>> {
static constexpr std::vector<T> get() { return std::vector<T>(); }
};
int main()
{
const auto n{ neutral<std::vector<int>>::get() };
const auto m{ neutral<float>::get() };
}

Boost MPL Sorting Template Parameter Pack

The problem I'm trying to solve is to sort a template parameter pack according to the return value of a constexpr templated function specialized for each of the types I'm sorting.
I have a list of approximately 100 BOOST_STRONG_TYPEDEFs which creates types TYPE_1, TYPE_2, ..., TYPE_N.
BOOST_STRONG_TYPEDEF(TYPE_1, int)
BOOST_STRONG_TYPEDEF(TYPE_2, double)
// et cetera
BOOST_STRONG_TYPEDEF(TYPE_N, uint8_t)
Then I declare a general template constexpr size_t value_of() for which I specialize for each one of my types:
template<> constexpr size_t value_of<TYPE_1>() { return 1; }
template<> constexpr size_t value_of<TYPE_2>() { return 2; }
// et cetera
template<> constexpr size_t value_of<TYPE_N>() { return n; }
Then I have a class declared as follows. I need to sort each of the types in the UnsortedTypes parameter pack according to the result of value_of.
template<typename ...UnsortedTypes>
class MyClass {
typedef boost::mpl::vector<UnsortedTypes...> UnsortedTypeVector;
typedef typename boost::mpl::sort<
UnsortedTypeVector,
boost::mpl::less<
boost::mpl::size_t<value_of<boost::mpl::placeholders::_1>()>,
boost::mpl::size_t<value_of<boost::mpl::placeholders::_2>()>
>
>::type SortedTypes;
// Utility
void print_types() {
__print_types<SortedTypes>();
}
template<typename Type, typename ...Types>
void __print_types() {
std::cout << typeid(Type).name() << "\n";
if constexpr (sizeof...(Types) > 0) __print_types<Types...>();
}
};
When I test it out as follows:
int main(int, char *[]) {
MyClass<TYPE_5, TYPE_3, TYPE_4, TYPE_2, TYPE_1> myclass;
myclass.print_types();
}
I get this huge, pretty much unintelligible error message which seems to consist of errors within the mpl library.
Intuitively, I have a suspicion that this results from an incorrect definition of my sorting predicate. However, I'm not sure how to fix it!
(This is my first time using Boost.MPL and there aren't many examples online, so please be gentle!)
Here's a reduced example that might make it more obvious what's going on:
namespace mpl = boost::mpl;
template <typename T> constexpr size_t value_of() { return sizeof(T); }
template <typename... Ts>
struct X {
using V = mpl::vector<Ts...>;
using sorted = typename mpl::sort<
V,
mpl::less<
mpl::size_t<value_of<mpl::_1>()>,
// ~~~~~~~~~~~~~~~~~~~
mpl::size_t<value_of<mpl::_2>()>
>
>::type;
};
Now, you intended that this delays the invocation of value_of() until _1 is substituted into. But actually what happens is that it's invoked immediately - because that's what you're asking for. In my case, that's whatever sizeof(_1) ends up being. And so, since these are all constants, the full mpl::less<...> is just some integral constant expression - rather than being a lambda expression, like you wanted it to be.
What you need to do is ensure that invocation is delayed by turning your predicate into a metafunction:
template <typename T>
struct value_of_ : mpl::size_t<sizeof(T)> { };
And then you can use:
template <typename... Ts>
struct X {
using V = mpl::vector<Ts...>;
using sorted = typename mpl::sort<
V,
mpl::less<value_of_<mpl::_1>, value_of_<mpl::_2>>
>::type;
};

Visibility of member functions in a CRTP class

I am writing a sorting library with sorter function objects. One of the main classes, sorter_facade, is intended to provide some overloads of operator() to the sorter depending on the overloads that already exist. Here is a simple reduced example of a heap_sorter object, implementing a heapsort:
struct heap_sorter:
sorter_facade<heap_sorter>
{
using sorter_facade<heap_sorter>::operator();
template<typename Iterator>
auto operator()(Iterator first, Iterator last) const
-> void
{
std::make_heap(first, last);
std::sort_heap(first, last);
}
};
One of the simplest goals of sorter_facade is to provide an iterable overload to the sorter's operator() when an overload taking a pair of iterators already exists. Here is a reduced implementation of sorter_facade, sufficient for the problem at hand:
template<typename Sorter>
struct sorter_facade
{
template<typename Iterable>
auto operator()(Iterable& iterable) const
-> std::enable_if_t<
not has_sort<Sorter, Iterable>,
decltype(std::declval<Sorter&>()(std::begin(iterable), std::end(iterable)))
>
{
return Sorter{}(std::begin(iterable), std::end(iterable));
}
};
In this class, has_sort is a trait used to detect whether a sorter has an operator() overload taking an Iterable&. It is implemented using a hand-rolled version of the detection idiom:
template<typename Sorter, typename Iterable>
using has_sort_t = std::result_of_t<Sorter(Iterable&)>;
template<typename Sorter, typename Iterable>
constexpr bool has_sort = std::experimental::is_detected_v<has_sort_t, Sorter, Iterable>;
Now, to the actual problem: the following main works well with g++ 5.2:
int main()
{
std::vector<int> vec(3);
heap_sorter{}(vec);
}
However, it fails with clang++ 3.7.0, with the following error message:
main.cpp:87:5: error: no matching function for call to object of type 'heap_sorter'
heap_sorter{}(vec);
^~~~~~~~~~~~~
/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/type_traits:2388:44: note: candidate template ignored: disabled by 'enable_if' [with Iterable = std::vector<int, std::allocator<int> >]
using enable_if_t = typename enable_if<_Cond, _Tp>::type;
^
main.cpp:75:10: note: candidate function template not viable: requires 2 arguments, but 1 was provided
auto operator()(Iterator first, Iterator last) const
^
1 error generated.
Apparently, when evaluating the std::enable_if_t, it seems to consider that Sorter already has an operator() able to take an Iterable&, which probably means that clang++ and g++ do not valuate the "same" Sorter when checking for the existence of the overload.
For this simple example, removing the std::enable_if_t makes the whole thing work, but the class sorter_facade is actually much bigger than that and I need it to resolve ambiguity problems with other overloads of operator(), so just removing it isn't a solution.
So... what causes the error? Should compilers accept or reject this code? Finally, is there a standard-compatible way to make this work with the latest versions of g++ and clang++?
EDIT: as a side note, I managed to get all the crazy to work with both g++5 and clang++3.8 by adding another layer of black magic to the point I've no idea why it even works anymore at all. While of all the previous questions hold, here is the « workaround » (using C++17 std::void_t):
tempate<typename Sorter>
struct wrapper:
Sorter
{
#ifdef __clang__
using Sorter::operator();
template<typename Iterable>
auto operator()(Iterable& iterable) const
-> std::enable_if_t<false, std::void_t<Iterable>>
{}
#endif
};
template<typename Sorter>
struct sorter_facade
{
template<typename Iterable>
auto operator()(Iterable& iterable) const
-> std::enable_if_t<
not has_sort<wrapper<Sorter>, Iterable>,
decltype(std::declval<Sorter&>()(std::begin(iterable), std::end(iterable)))
>
{
return Sorter{}(std::begin(iterable), std::end(iterable));
}
};
I guess that it abuses different compiler-specific behaviours in both g++ and clang++ and achieves something that wasn't meant to work, but still... I'm amazed that it works, even in my whole project, which has many more tricky things to handle...
I am pretty sure this is a bug in clang. The return type of sorter_facade<Sorter>::operator() depends on the template argument Iterator. Still, the compiler seems to decide to SFINAE out before knowing the arguments.
But bug or not, you can work around this by explicitly deferring the calculation of the return type. Here is a version that does not depend on black magic. Works with gcc-5.2 and clang-3.6:
template<typename Sorter, typename Iterable>
struct sort_result
{
using type = decltype(
std::declval<Sorter&>()(
std::begin(std::declval<Iterable&>()),
std::end(std::declval<Iterable&>())));
};
template<typename Sorter, typename Deferred>
using sort_result_t = typename sort_result<Sorter, Deferred>::type;
template<typename Sorter>
struct sorter_facade
{
template <typename Iterable>
auto operator()(Iterable& iterable) const
-> sort_result_t<Sorter, Iterable>
{
return Sorter{}(std::begin(iterable), std::end(iterable));
}
};
struct heap_sorter:
sorter_facade<heap_sorter>
{
using sorter_facade<heap_sorter>::operator();
template<typename Iterator>
auto operator()(Iterator first, Iterator last) const
-> void
{
std::make_heap(first, last);
std::sort_heap(first, last);
}
};
int main()
{
std::vector<int> vec(3);
heap_sorter{}(vec);
}
The trick is: The compiler does not know if you specialize the result_type later on. Therefore it has to wait until you actually use it, before trying to determine the return type.

How do I use boost::transformed to modify a sequence using a lambda in a template construct?

I have a type MyStruct which I would like to produce some "sequence" from, where each instance of MyStruct is generated from passing to its constructor an element of another range as well as the output of some function.
The function itself (SomeFun) is a member function in another class, but for this example I'll make it a free function. However, keep in mind that I can's simply place it inside the lambda or do other tricky things to avoid the need for a lambda because I do need to actually pass a this pointer around in my actual case.
Here is a simplified, testable version to illustrate the problem I'm having:
#include <iostream>
#include <vector>
#include <boost/range/adaptor/transformed.hpp>
#include <functional>
template <typename RowType>
class MyStruct;
template <typename T>
int SomeFun(T t)
{
return 0;
}
template <typename Sequence>
using Converter = std::function<
MyStruct<typename Sequence::value_type>(
typename Sequence::value_type&)>;
template <typename Sequence>
boost::transformed_range<Converter<Sequence>, Sequence>
GenerateTransformedRange(const Sequence& outputs)
{
std::function<MyStruct<typename Sequence::value_type>(int)> fun =
[](const typename Sequence::value_type output)
{
return MyStruct<typename Sequence::value_type>(output, SomeFun(output));
};
return outputs | boost::adaptors::transformed(fun);
}
// some structure
template <typename T>
struct MyStruct
{
MyStruct(T t, int a)
{
}
};
int main(int argc, const char* argv[])
{
std::vector<int> vec {1, 2, 3};
for (auto element : GenerateTransformedRange(vec))
{
}
return 0;
}
The output from this is:
main.cpp:31:54: error: could not convert
‘boost::range_detail::operator|(const InputRng&, const
boost::range_detail::transform_holder&) [with InputRng
= std::vector; UnaryFunction = std::function(int)>]((*(const
boost::range_detail::transform_holder(int)>
)(& boost::range_detail::forwarder::operator()(T) const [with T = std::function(int)>; Holder =
boost::range_detail::transform_holder](std::function(int)>(((const
std::function(int)>*)(& fun)))))))’ from
‘boost::range_detail::transformed_range(int)>,
const std::vector >’ to
‘boost::range_detail::transformed_range(int&)>,
std::vector >’
return outputs | boost::adaptors::transformed(fun);
^ makefile:25: recipe for target '.obj/main.o' failed
What am I doing wrong here? I don't quot understand why it wants to convert from that type. Any ideas? I'm using Boost 1.55.
The error:
test.cpp:29:20: error: no match for ‘operator|’ (operand types are ‘const std::vector’ and ‘std::function >(int)>’)
return outputs | fun;
should be perfectly clear. There is no operator| for operands vector and a function. Your second operand should be a boost adaptor which actually defines the operator. Probably like this:
return outputs | boost::adaptors::transformed(fun);
Also in this code:
std::function<MyStruct<Sequence>(int)> fun =
[](const typename Sequence::value_type output)
{
return MyStruct<typename Sequence::value_type>(output, SomeFun(output));
};
According to the type declaration, fun should return a MyStruct<Sequence> but your lambda returns a MyStruct<typename Sequence::value_type>. Also, you probably shouldn't hardcode the parameter type as int if the lambda expects a Sequence::value_type. You should probably declare fun as type Converter<Sequence>. Also, fix the parameter type of the lambda and the function to match with Converter (pay attention to the reference).

c++ functions as template arguments

I'm experiencing some problems which can be resumed by the following piece of code:
template <typename Key, typename Data, typename fct>
size_t wrapper(const std::pair<Key, Data> & p)
{
return fct(p.first);
}
int main(int argc, char *argv[])
{
size_t val =
wrapper<int, int, dft_hash_fct<int>>(std::pair<int,int>(5,9));
return 0;
}
I'm using clang compiler version 3.4 and this code does not compile with the following error
test-tmp.C:17:5: error: no matching function for call to 'wrapper'
wrapper<int, int, dft_hash_fct<int>>(std::pair<int,int>(5,9));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test-tmp.C:9:8: note: candidate template ignored: invalid explicitly-specified argument
for template parameter 'fct'
The idea is to wrap a hash function (the template parameter fct) on std::pair for only taking the first field.
dft_hash_fct is another template defines as follows:
template <typename Key>
size_t dft_hash_fct(const Key & key)
{
return SuperFastHash(key);
}
This generic function works; it has been used in other contexts.
The purpose of all this is to reuse a hash based set (not map) as a map of keys to items of any type. The hash based ser receives a hash function in construction time.
Thanks for your comments (David, Andrey and Kazark)
Edited:
Well, I see, typename fct is a type, so I cannot handle as a pointer function; sorry for the trivia. Unfortunately, I believe that the approach of passing the function as parameter in the wrapper does not work, because the hash set expects a function pointer with the following signature:
size_t (*the_function)(const Key & key);
So, realizing this, thanks to your observations, I changed the code in question to:
template <typename Key, typename Data, size_t (*fct)(const Key & k)>
size_t wrapper(const std::pair<Key, Data> & p)
{
return (*fct)(p.first);
}
int main(int argc, char *argv[])
{
size_t val =
wrapper<int, int, dft_hash_fct<int>>(std::pair<int,int>(5,9));
return 0;
}
that compiles, links and runs. In addition, I put this line:
size_t (*fct)(const std::pair<int, int>&) =
wrapper<int, int, dft_hash_fct<int>>;
cout << (*fct)(std::pair<int, int>(4,6)) << endl;
And that compiles, links ans runs too. So, I can say that the compiler (and of course according to the language) can instantiate the function and handle a function pointer to it.
So, after that I tried to modify my original code, which is a derived class of HAshSet intended for managing pairs hashed by first field.
I declare some as:
template <typename Key, typename Data>
class HashMap : public HashSet<std::pair<Key, Data>>
{
...
HashMap(size_t (*function)(const Key & key))
: HashSet<Key, Data>(wrapper<Key, Data, function>)
{
}
..
};
But the compilation (with std=c++11) fails with the error
./tpl_dynSetHash.H:353:7: error: no matching constructor for initialization of
'HashSet<std::pair<unsigned long, long>>'
: HashSet<std::pair<Key,Data>(
^
testDynSetHash.C:178:8: note: in instantiation of member function
'HashMap<unsigned long, long>::HashMap' requested here
HMap table;
However, if I substitute the call to base constructor by
: HashSet<Key, Data>(wrapper<Key, Data, dft_hash_fct<Key>)
That compiles fine. Thus, I believe that the problem is with the parameter type declaration (but I do not know what is).
The standard idiom to pass functions is to pass them as function objects, e.g.
template <typename Key, typename Data, typename Fct>
size_t wrapper(const std::pair<Key, Data> & p, Fct fct)
{
return fct(p.first);
}
Then call the wrapper using:
int main(int argc, char *argv[])
{
// no explicit template arguments required
size_t val =
wrapper(std::pair<int,int>(5,9), &dft_hash_fct<int>);
return 0;
}
In your code, on the other hand:
template <typename Key, typename Data, typename fct>
size_t wrapper(const std::pair<Key, Data> & p)
{
return fct(p.first);
}
typename fct introduces an alias for a type. Inside this function, fct names a type; therefore fct(p.first) creates an object of type fct, and this object needs to be converted to a size_t in order to return it from wrapper. You can use this as well, but the type you had to use would have to look like this:
struct dft_hash_fct_t
{
size_t result;
dft_hash_fct_t(int p) : result(SuperFashHash(p)) {}
operator size_t() const { return result; }
};
Which is probably not what you intended.
The template declaration in
template <typename Key, typename Data, typename fct>
size_t wrapper(const std::pair<Key, Data> & p)
{
return fct(p.first);
}
declares template parameterfct as a type, but you are trying to pass a function pointer to it. You can make fct function pointer template parameter like this:
template <typename Key, typename Data, size_t(*fct)(const Key&)>
size_t wrapper(const std::pair<Key, Data> & p)
{
return fct(p.first);
}
However, the more idiomatic way is (as DyP says) to pass a function object so that the function works with function pointers as well as objects overloading operator():
template <typename Key, typename Data, typename Fct>
size_t wrapper(const std::pair<Key, Data> & p, Fct fct)
{
return fct(p.first);
}
Then when calling it you pass the function as a parameter
wrapper(std::pair<int,int>(5,9), dft_hash_fct<int>);
The code you wrote makes no sense within the context of your intent. Your fct template parameter is a type. That means that
return fct(p.first);
is a function-style cast, not an application of () operator (i.e. it is not a function call). In your code you are attempting to cast p.first to type fct and then attempting to return the result of that cast as size_t. Was that your intent? I doubt that it was. On top of that you are trying to pass a function pointer value dft_hash_fct<int> as a template argument for fct, i.e. you are passing a value where a type is expected. How did you expect it to work?
The description you provided seems to imply that you actually wanted to call a functor with type fct from inside wrapper instead of performing a cast. In order to do that you have to obtain the functor itself somehow. Remember again that fct is not a functor, its is just the type of the functor.
The typical approach would be to pass the functor from the outside, as function parameter
template <typename Key, typename Data, typename fct>
size_t wrapper(const std::pair<Key, Data> & p, fct f)
{
return f(p.first);
}
Now you can use your wrapper template with class-based functors, as well as with ordinary functions
size_t val = wrapper(std::pair<int,int>(5,9), dft_hash_fct<int>);
Note that dft_hash_fct<int> has to be supplied as function argument, not as template argument.
There's no need to explicitly specify template arguments, since they will be deduced by the compiler.