Does/would c++11/14 support something like vector<auto> - c++11

I am wondering if c++11/c++14 would/already support something like vector<auto>?
If not, Is there any reason?

It's not supported directly, and not immediately clear exactly what you want it to do.
Comments have already mentioned a couple of possibilities (such as Boost any and variant classes) for creating heterogeneous collections. I hope this isn't what you were after, because heterogeneous collections fit poorly with C++ so using them is ugly and clumsy. I suppose there are cases/situations where these really would be the best choices available, but at least in my experience, those cases are fairly rare.
Another possible interpretation of what you might want would be a vector that (like auto in general) holds exactly one type, but that type is deduced from the initializer, so if you initialized the vector from some ints, you'd get a vector<int>, and if you initialized it from some strings, you'd get a vector<string>, and so on. Although the language doesn't support that directly, it is pretty easy to simulate it to at least some degree. Template classes can't/don't ever deduce template parameters, but template functions do/can. Therefore, we can create a tiny function template to take some initializers, deduce their type, and return a vector of that type. For example:
template <class T>
std::vector<T> make_vector(std::initializer_list<T> init) {
return std::vector<T>(init);
}
This returns a vector<T> (with T deduced from the type of data in the initializer list), so you can do things like:
auto a = make_vector({ 1, 2, 3, 4 }); // a -> vector<int>
auto b = make_vector({ 1.0, 2.0, 3.0 }); // b -> vector<double>
auto c = make_vector({ "1"s, "2"s, "3"s }); // c -> vector<std::string>
That last one requires a user-defined literal operator that's new in C++14 (which many compilers don't yet support). The rest should be fine with C++11.
There has also been some discussion (and a proposal in N3602) of adding a capability (perhaps to C++17) where you'd be able to define something like the make_vector above, but as something like a templated constructor for the class. This would let you use argument deduction on the constructor to deduce the template parameter for the class as a whole, so you'd be able to do something like:
X x(1); // deduces as X<int>
X x(2.0) // deduces as X<double>
Warning though: this has been proposed but not accepted. It may (easily) never be accepted--and even if it is, it may be altered significantly before that happens.

No, not in C++11 or C++14, which are already finished and published.
But it's possible that vector<auto> and similar things like tuple<auto...> will be in C++17 as part of the Concepts work.
It follows quite naturally from the fact that std::vector<T> can be used in function templates and class template partial specializations where T is a template parameter, and also from the fact that polymorphic lambdas allow auto as a function parameter type (which is shorthand for a function template with deduced parameters).
The Concepts TS allows a "generic function" to be declared like:
auto func(auto arg);
Since you can have a function template like this:
template<typename T>
auto func(std::vector<T> v);
it makes sense to extend the generic function syntax to allow:
auto func(std::vector<auto> v);
and once you allow that in a function declaration, it should also be possible to allow it in variable declarations:
std::vector<auto> v = function_returning_vector_of_something();
The reason it isn't in C++11 is that auto was new, and it would have been too ambitious to try and make it do too much. In C++14 polymorphic lambdas were new, and again, expanding the uses of auto any further would have been ambitious.
For C++17 we have more experience with using auto in real code, and compiler writers are familiar with implementing it and know what is possible without too much effort.

A boost::any can store an instance of any type that can be copied, which is a lot of types.
In order to get the data out of your any, you have to know the exact type you stored in it.
Writing a simple any isn't hard:
#include <memory>
#include <utility>
struct any_internal {
virtual any_internal* clone() const = 0;
virtual ~any_internal() {};
};
template<class T>
struct any_details;
class any {
std::unique_ptr<any_internal> internal;
public:
any() = default;
any( any && ) = default;
any( any const&& o):any(o) {}
any( any & o ):any( const_cast<any const&>(o) ) {}
any& operator=( any && ) = default;
any& operator=( any const&& o ) { return this->operator=( o ); };
any& operator=( any & o ) { return this->operator=( const_cast<any const&>(o) ); };
any( any const& o ):internal( o.internal?o.internal->clone():nullptr ) {}
any& operator=( any const& o ) {
any tmp(o);
using std::swap;
swap( internal, tmp.internal );
return *this;
}
template<class U>
void reset( U&& o );
template<class U, class... Args>
void emplace( Args&&... args );
template<class U>
any( U&& o );
template<class U>
any& operator=(U&& o);
template<class T> T* get();
template<class T> T const* get() const;
template<class T> T* fast_get();
template<class T> T const* fast_get() const;
explicit operator bool() const { return internal!=nullptr; }
};
template<class T>
struct any_details : any_internal {
T t;
template<class...Args>
any_details( Args&&... args ):t(std::forward<Args>(args)...) {}
any_internal* clone() const override { return new any_details<T>{t}; }
};
template<class U, class... Args>
void any::emplace( Args&&... args ) {
internal.reset( new any_details<U>( std::forward<Args>(args)... ) );
}
template<class U>
void any::reset( U&& o ) {
emplace<typename std::decay<U>::type>( std::forward<U>(o) );
}
template<class U>
any::any( U&& o ) {
reset( std::forward<U>(o) );
}
template<class U>
any& any::operator=(U&& o) {
reset( std::forward<U>(o) );
return *this;
}
template<class T> T* any::get() {
auto* r = dynamic_cast< any_details<T>* >( internal.get() );
if (r) return &r->t;
return nullptr;
}
template<class T> T const* any::get() const {
auto* r = dynamic_cast< any_details<T>* >( internal.get() );
if (r) return &r->t;
return nullptr;
}
template<class T> T* any::fast_get() {
auto* r = static_cast< any_details<T>* >( internal.get() );
if (r) return &r->t;
return nullptr;
}
template<class T> T const* any::fast_get() const {
auto* r = static_cast< any_details<T>* >( internal.get() );
if (r) return &r->t;
return nullptr;
}
and a std::vector<any> behaves much like you might want a std::vector<auto> to do.
Increased efficiency can be achieved via small buffer optimizations (ie, store the T within the any if the t is small, instead of using the heap).
You'd probably also want to split get from fast_get, where get does a dynamic_cast and fast_get does a static_cast, again for efficiency. (When you know for certain, you can fast_get)
Basically this is a gussied up void*.

Related

How to set a function as a default parameter?

I ran into a problem with setting a function as a default parameter.
The following code doesn't make a lot of sense. What I want to achieve can be done in many different ways. This code only describes the problem I ran into and wish to know how to fix it to work to my specifications.
#include <iostream>
#include <vector>
int double_the_number(int x)
{
return x * 2;
}
template<typename T, typename FunctionType>
std::vector<FunctionType> copy_with_criteria(T iter1, T iter2, FunctionType F(FunctionType))
{
std::vector<int> new_vector;
while(iter1 != iter2)
{
new_vector.push_back(F(*iter1++));
}
return new_vector;
}
int main()
{
std::vector<int> v {1,2,3,4,5};
auto new_vector = copy_with_criteria(v.begin(), v.end(), double_the_number);
for(int x : new_vector) std::cout << x << " ";
return 0;
}
When the code above is ran, it will output 2 4 6 8 10
What I want to achieve is if I call a function without specifying the criteria function copy_with_criteria(v.begin(), v.end()) I want it to output 1,2,3,4,5
That is, somehow I would like to set the function as a default parameter which is a type of elements inside some container (in this case vector) and which returns number that has been sent to it, like this (TypeOfElements is just an example of what type the default criteria function should be):
TypeOfElements default_function(TypeOfElements x) {
return x;
}
I would not like to use any external libraries. Also I am working with c++11.
If anyone could help me with this problem I would be very grateful!
Thank you :)
Overload your function.
template <typename T>
std::vector<typename std::iterator_traits<T>::value_type>
copy_with_criteria(T iter1, T iter2)
{
return std::vector<typename std::iterator_traits<T>::value_type>(iter1, iter2);
}
You can define your function as:
template<typename T, typename FunctionType = typename std::decay<decltype(*std::declval<T>())>::type>
std::vector<FunctionType> copy_with_criteria(T iter1, T iter2, FunctionType(*F)(FunctionType) = [](FunctionType v){ return v; }) {
// ...
}
It works in C++11 as requested (see it on Coliru).
The basic idea is that you can deduce FunctionType directly from the type of the iterators and not from the function F. Then you can give to F a default by using a lambda function that is nothing more than an identity function.
Otherwise you can simply overload copy_with_criteria as suggested by aschepler (I'd rather go with his approach instead of using a default argument) or simply define a different function with a meaningful name that is explicit about your intention for you are not using criteria during that kind of copy.
Edit
As suggested by #aschepler in the comments, you can use iterator_traits<T>::value_type instead of typename std::decay<decltype(*std::declval<T>())>::type to avoid problems with some types.
Functions are the wrong thing to use here. State can easily be useful. You want to use a generic function object. And deduce the return value.
In addition, using iterator ranges is questionable. The next iteration of C++ range library is going to reduce that use.
While you want a C++11 solution, there is no reason to use the C++03/C++11 style. Be forward looking.
So let us get started.
#include <iterator>
namespace notstd {
namespace adl_helper {
using std::begin; using std::end;
template<class C>
auto adl_begin( C&& )
-> decltype( begin( std::declval<C>() ) );
template<class T, std::size_t N>
auto adl_begin( T(*)[N] )
-> T*;
}
template<class C>
using iterator_type=decltype(
::notstd::adl_helper::adl_begin( std::declval<C>() )
);
}
This finds the iterator type of a container via calling std::begin in an ADL-enabled context. This emulates what a for(:) loop does reasonably well.
namespace notstd {
template<class C>
using value_type = typename std::iterator_traits<
iterator_type<C>
>::value_type;
}
now we can value_type<C> for some type C and get the type it contains.
namespace notstd {
struct make_a_copy_t {
template<class T>
auto operator()(T&& t)const
-> std::decay_t<T>
{
return std::forward<T>(t);
}
};
}
make_a_copy_t is a functor that copies stuff.
We are almost ready to solve your problem.
template<class Op=notstd::make_a_copy_t, class C,
class R=decltype( std::declval<Op&>()(std::declval<notstd::value_type<C&>>()) )
>
std::vector<R>
copy_with_criteria(C&& c, Op op={})
{
std::vector<R> new_vector;
for (auto&& e:std::forward<C>(c))
{
new_vector.push_back( op(decltype(e)(e)) );
}
return new_vector;
}
and I believe this satisfies your criteria.
You may also need
namespace notstd {
template<class It>
struct range_t {
It b = {};
It e = {};
It begin() const { return b; }
It end() const { return e; }
range_t( It s, It f ):b(std::move(s)), e(std::move(f)) {}
range_t( It s, std::size_t count ):
range_t( s, std::next(s, count) )
{}
range_t() = default;
range_t(range_t&&)=default;
range_t(range_t const&)=default;
range_t& operator=(range_t&&)=default;
range_t& operator=(range_t const&)=default;
range_t without_front(std::size_t N)const {
return {std::next(begin(), N), end()};
}
range_t without_back(std::size_t N)const {
return {begin(), std::prev(end(),N)};
}
std::size_t size() const {
return std::distance(begin(), end());
}
// etc
};
template<class It>
range_t<It> range( It b, It e ) {
return {std::move(b), std::move(e)};
}
template<class It>
range_t<It> range( It b, std::size_t count ) {
return {std::move(b), count};
}
template<class C>
range_t<iterator_type<C&>> range( C& c ) {
using std::begin; using std::end;
return {begin(c), end(c)};
}
}
which lets you do operations on subsections of a container as a range.
So suppose you want to take the first half of a vector of int and double it.
std::vector<int> some_values{1,2,3,4,5,6,7,8,9,10};
auto front_half = notstd::range(some_values).without_back(some_values.size()/2);
auto front_doubled = copy_with_criteria( front_half, [](int x){return x*2;} );
and done.
Live example.

Deduce type of container from iterator (when possible)

Is it possible to detect the container type from the iterator type?
For example,
#include<traits>
int main(){
static_assert(std::is_same<
container_of<std::vector<double>::iterator>::type, std::vector<double>>{});
static_assert(std::is_same<
container_of<std::list<int>::iterator>::type, std::list<int>>{});
}
(Of course some iterators type will not give a container (or not give a unique container), for example a raw pointer or a stream iterator, but in those cases it can soft-SFINAE-fail.)
The first attempt is
template<class T, template<class> class Cont> Cont<T> aux(typename Cont<T>::iterator it);
template<class Iterator> struct container_of{
using type = decltype(aux(Iterator{}));
};
However, it doesn't work because the compiler can't detect the type of T (it is not in a deductible context).
Motivation: I want to detect whether the associated container of an iterator has a .data() member.
Instead of your primitive being an iterator, make your primitive be a range.
template<class It, bool Contiguous, class D=void>
struct range_t {
using Self = std::conditional< !std::is_same<D, void>, D, range_t >;
It b, e;
It begin() const { return b; }
It end() const { return e; }
Self without_front( std::size_t i = 1 ) const {
return {std::next(begin(), i), end()};
}
Self without_back( std::size_t i = 1 ) const {
return {begin(), std::prev(end(), i)};
}
bool empty() const { return begin()==end(); }
std::size_t size() const { return std::distance( begin(), end() ); }
};
template<class It>
struct range_t<It, true, void>:
range_t<It, false, range_t<It, true>>
{
using Base = range_t<It, false, range_t<It, true>>;
range_t( It b, It e ):Base(b,e) {}
auto* data() const {
if (empty()) return nullptr;
return std::addressof(*this->begin()); }
}
};
Track (manually) what containers are contiguous:
template<class T, class=void>
struct is_contiguous_container : std::false_type{};
template<class T>
struct is_contiguous_container<T const, void> : is_contiguous_container<T> {};
template<class T>
struct is_contiguous_container<T volatile, void> : is_contiguous_container<T> {};
template<class T>
struct is_contiguous_container<T const volatile, void> : is_contiguous_container<T> {};
template<class T>
struct is_contiguous_container<T, std::enable_if_t< has_data_ptr<T>{} >>:
std::true_type{};
template<class T, std::size_t N>
struct is_contiguous_container<T[N],void> : std::true_type{};
The contiguous containers are array, std::array and std::vector, so not much to track. range_t< ?, true, ? > is also contiguous. Just write has_data_ptr, that is true iff T.data() returns a pointer to non-void.
template<class C>
auto range( C&& c ) {
using std:begin; using std::end;
auto b = begin(c), e = end(c);
using It = decltype(b);
using R = range_t<It, is_contiguous_container<std::remove_reference_t<C>>{}>;
return R{ b, e };
}
range now smartly converts a container into a range_t, keeping track of if it is contiguous or not.
range_t supports r.without_front( r.size()/2 ) to divide and conquer.
When a range is contiguous, just call .data() on it. When it isn't, don't.
In your application if you just want to know whether the container has a .data() member, it might be enough for you to check if it is random access (using std::iterator_traits<Iter>::iterator_category()).
Otherwise, I think you might be able to use a combination of the technique in: How to check if two types come from the same templated class and partial specialization for every standard container type.
Or wait for c++17 which has a new contiguous iterator concept: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4284.html
What I am doing at the moment is to manually register all (some really) of the iterators that are contiguous.
Since I will always need this in combination with some way to extract the raw pointer, I directly code a single function called data that returns the pointer.
The code is not funny, it considers std::vector<>::iterator, std::basric_string<>::iterator, for illustration (to show that it will always be incomplete) I also added boost::static_vector<>, raw pointer and anything convertible to a pointer. (boost::array<>::iterator and std::array<>::iterator and begin/end(std::valarray) are effectively included because the iterators are pointers).
I also had to include the const_iterator cases.
#include<type_traits>
#include<vector> // the code below needs to know about std::vector
#include<boost/container/static_vector.hpp> // ... and all possible contigous containers :(
template<
class ContiguousIterator, // well ProbablyContiguos
typename = std::enable_if_t<
/**/std::is_same<ContiguousIterator, typename std::vector<std::decay_t<decltype(*std::declval<ContiguousIterator>())>>::iterator>{}
or std::is_same<ContiguousIterator, typename std::vector<std::decay_t<decltype(*std::declval<ContiguousIterator>())>>::const_iterator>{}
or std::is_same<ContiguousIterator, typename std::basic_string<std::decay_t<decltype(*std::declval<ContiguousIterator>())>>::iterator>{}
or std::is_same<ContiguousIterator, typename boost::container::static_vector<std::decay_t<decltype(*std::declval<ContiguousIterator>())>, 1>::iterator>{}
or std::is_same<ContiguousIterator, typename boost::container::static_vector<std::decay_t<decltype(*std::declval<ContiguousIterator>())>, 1>::const_iterator>{}
// many many other possible iterators :(
or std::is_pointer<ContiguousIterator>{}
or std::is_constructible<typename std::iterator_traits<ContiguousIterator>::pointer, ContiguousIterator>{}
>
>
typename std::iterator_traits<ContiguousIterator>::pointer
data(ContiguousIterator const& it){return std::addressof(*it);}
int main(){
std::vector<double> v(30);
v[0] = 10.;
assert( *data(v.begin()) == 10. );
}
Feedback is welcomed.

Looking for "is_comparable" typetrait

I'm looking for an "is_comparable" typetrait but can't find any.
It's very easy to build one that checks if an operator== for a class was implemented, but this excludes global defined operators.
Is it impossible to implement a is_comparable typetait?
I take it you mean a trait that, for two types L and R and
objects lhs and rhs of those types respectively, will yield true if
the lhs == rhs will compile and false otherwise. You appreciate that
in theory lhs == rhs might compile even though rhs == lhs, or lhs != rhs,
does not.
In that case you might implement the trait like:
#include <type_traits>
template<class ...> using void_t = void;
template<typename L, typename R, class = void>
struct is_comparable : std::false_type {};
template<typename L, typename R>
using comparability = decltype(std::declval<L>() == std::declval<R>());
template<typename L, typename R>
struct is_comparable<L,R,void_t<comparability<L,R>>> : std::true_type{};
This applies a popular SFINAE pattern for defining traits that is explained
in the answer to this question
Some illustrations:
struct noncomparable{};
struct comparable_right
{
bool operator==(comparable_right const & other) const {
return true;
}
};
struct any_comparable_right
{
template<typename T>
bool operator==(T && other) const {
return false;
}
};
bool operator==(noncomparable const & lhs, int i) {
return true;
}
#include <string>
static_assert(is_comparable<comparable_right,comparable_right>::value,"");
static_assert(!is_comparable<noncomparable,noncomparable>::value,"");
static_assert(!is_comparable<noncomparable,any_comparable_right>::value,"");
static_assert(is_comparable<any_comparable_right,noncomparable>::value,"");
static_assert(is_comparable<noncomparable,int>::value,"");
static_assert(!is_comparable<int,noncomparable>::value,"");
static_assert(is_comparable<char *,std::string>::value,"");
static_assert(!is_comparable<char const *,char>::value,"");
static_assert(is_comparable<double,char>::value,"");
If you want the trait to require that equality is symmetric and that inequality
also exists and is symmetric you can see how to elaborate it yourself.

Persistent expression templates with unique_ptr and matrices

I want to use expression templates to create a tree of objects that persists across statement. Building the tree initially involves some computations with the Eigen linear algebra library. The persistent expression template will have additional methods to compute other quantities by traversing the tree in different ways (but I'm not there yet).
To avoid problems with temporaries going out of scope, subexpression objects are managed through std::unique_ptr. As the expression tree is built, the pointers should be propagated upwards so that holding the pointer for the root object ensures all objects are kept alive. The situation is complicated by the fact that Eigen creates expression templates holding references to temporaries that go out of scope at the end of the statement, so all Eigen expressions must be evaluated while the tree is being constructed.
Below is a scaled-down implementation that seems to work when the val type is an object holding an integer, but with the Matrix type it crashes while constructing the output_xpr object. The reason for the crash seems to be that Eigen's matrix product expression template (Eigen::GeneralProduct) gets corrupted before it is used. However, none of the destructors either of my own expression objects or of GeneralProduct seems to get called before the crash happens, and valgrind doesn't detect any invalid memory accesses.
Any help will be much appreciated! I'd also appreciate comments on my use of move constructors together with static inheritance, maybe the problem is there somewhere.
#include <iostream>
#include <memory>
#include <Eigen/Core>
typedef Eigen::MatrixXi val;
// expression_ptr and derived_ptr: contain unique pointers
// to the actual expression objects
template<class Derived>
struct expression_ptr {
Derived &&transfer_cast() && {
return std::move(static_cast<Derived &&>(*this));
}
};
template<class A>
struct derived_ptr : public expression_ptr<derived_ptr<A>> {
derived_ptr(std::unique_ptr<A> &&p) : ptr_(std::move(p)) {}
derived_ptr(derived_ptr<A> &&o) : ptr_(std::move(o.ptr_)) {}
auto operator()() const {
return (*ptr_)();
}
private:
std::unique_ptr<A> ptr_;
};
// value_xpr, product_xpr and output_xpr: expression templates
// doing the actual work
template<class A>
struct value_xpr {
value_xpr(const A &v) : value_(v) {}
const A &operator()() const {
return value_;
}
private:
const A &value_;
};
template<class A,class B>
struct product_xpr {
product_xpr(expression_ptr<derived_ptr<A>> &&a, expression_ptr<derived_ptr<B>> &&b) :
a_(std::move(a).transfer_cast()), b_(std::move(b).transfer_cast()) {
}
auto operator()() const {
return a_() * b_();
}
private:
derived_ptr<A> a_;
derived_ptr<B> b_;
};
// Top-level expression with a matrix to hold the completely
// evaluated output of the Eigen calculations
template<class A>
struct output_xpr {
output_xpr(expression_ptr<derived_ptr<A>> &&a) :
a_(std::move(a).transfer_cast()), result_(a_()) {}
const val &operator()() const {
return result_;
}
private:
derived_ptr<A> a_;
val result_;
};
// helper functions to create the expressions
template<class A>
derived_ptr<value_xpr<A>> input(const A &a) {
return derived_ptr<value_xpr<A>>(std::make_unique<value_xpr<A>>(a));
}
template<class A,class B>
derived_ptr<product_xpr<A,B>> operator*(expression_ptr<derived_ptr<A>> &&a, expression_ptr<derived_ptr<B>> &&b) {
return derived_ptr<product_xpr<A,B>>(std::make_unique<product_xpr<A,B>>(std::move(a).transfer_cast(), std::move(b).transfer_cast()));
}
template<class A>
derived_ptr<output_xpr<A>> eval(expression_ptr<derived_ptr<A>> &&a) {
return derived_ptr<output_xpr<A>>(std::make_unique<output_xpr<A>>(std::move(a).transfer_cast()));
}
int main() {
Eigen::MatrixXi mat(2, 2);
mat << 1, 1, 0, 1;
val one(mat), two(mat);
auto xpr = eval(input(one) * input(two));
std::cout << xpr() << std::endl;
return 0;
}
Your problem appears to be that you are using someone else's expression templates, and storing the result in an auto.
(This happens in product_xpr<A>::operator(), where you call *, which if I read it right, is an Eigen multiplication that uses expression templates).
Expression templates are often designed to presume the entire expression will occur on a single line, and it will end with a sink type (like a matrix) that causes the expression template to be evaluated.
In your case, you have a*b expression template, which is then used to construct an expression template return value, which you later evaluate. The lifetime of temporaries passed to * in a*b are going to be over by the time you reach the sink type (matrix), which violates what the expression templates expect.
I am struggling to come up with a solution to ensure that all temporary objects have their lifetime extended. One thought I had was some kind of continuation passing style, where instead of calling:
Matrix m = (a*b);
you do
auto x = { do (a*b) pass that to (cast to matrix) }
replace
auto operator()() const {
return a_() * b_();
}
with
template<class F>
auto operator()(F&& f) const {
return std::forward<F>(f)(a_() * b_());
}
where the "next step' is passed to each sub-expression. This gets trickier with binary expressions, in that you have to ensure that the evaluation of the first expression calls code that causes the second sub expression to be evaluated, and then the two expressions are combined, all in the same long recursive call stack.
I am not proficient enough in continuation passing style to untangle this knot completely, but it is somewhat popular in the functional programming world.
Another approach would be to flatten your tree into a tuple of optionals, then construct each optional in the tree using a fancy operator(), and manually hook up the arguments that way. Basically do manual memory management of the intermediate values. This will work if the Eigen expression templates are either move-aware or do not have any self-pointers, so that moving at the point of construction doesn't break things. Writing that would be challenging.
Continuation passing style, suggested by Yakk, solves the problem and isn't too insane (not more insane than template metaprogramming in general anyhow). The double lambda evaluation for the arguments of binary expressions can be tucked away in a helper function, see binary_cont in the code below. For reference, and since it's not entirely trivial, I'm posting the fixed code here.
If somebody understands why I had to put a const qualifier on the F type in binary_cont, please let me know.
#include <iostream>
#include <memory>
#include <Eigen/Core>
typedef Eigen::MatrixXi val;
// expression_ptr and derived_ptr: contain unique pointers
// to the actual expression objects
template<class Derived>
struct expression_ptr {
Derived &&transfer_cast() && {
return std::move(static_cast<Derived &&>(*this));
}
};
template<class A>
struct derived_ptr : public expression_ptr<derived_ptr<A>> {
derived_ptr(std::unique_ptr<A> &&p) : ptr_(std::move(p)) {}
derived_ptr(derived_ptr<A> &&o) = default;
auto operator()() const {
return (*ptr_)();
}
template<class F>
auto operator()(F &&f) const {
return (*ptr_)(std::forward<F>(f));
}
private:
std::unique_ptr<A> ptr_;
};
template<class A,class B,class F>
auto binary_cont(const derived_ptr<A> &a_, const derived_ptr<B> &b_, const F &&f) {
return a_([&b_, f = std::forward<const F>(f)] (auto &&a) {
return b_([a = std::forward<decltype(a)>(a), f = std::forward<const F>(f)] (auto &&b) {
return std::forward<const F>(f)(std::forward<decltype(a)>(a), std::forward<decltype(b)>(b));
});
});
}
// value_xpr, product_xpr and output_xpr: expression templates
// doing the actual work
template<class A>
struct value_xpr {
value_xpr(const A &v) : value_(v) {}
template<class F>
auto operator()(F &&f) const {
return std::forward<F>(f)(value_);
}
private:
const A &value_;
};
template<class A,class B>
struct product_xpr {
product_xpr(expression_ptr<derived_ptr<A>> &&a, expression_ptr<derived_ptr<B>> &&b) :
a_(std::move(a).transfer_cast()), b_(std::move(b).transfer_cast()) {
}
template<class F>
auto operator()(F &&f) const {
return binary_cont(a_, b_,
[f = std::forward<F>(f)] (auto &&a, auto &&b) {
return f(std::forward<decltype(a)>(a) * std::forward<decltype(b)>(b));
});
}
private:
derived_ptr<A> a_;
derived_ptr<B> b_;
};
template<class A>
struct output_xpr {
output_xpr(expression_ptr<derived_ptr<A>> &&a) :
a_(std::move(a).transfer_cast()) {
a_([this] (auto &&x) { this->result_ = x; });
}
const val &operator()() const {
return result_;
}
private:
derived_ptr<A> a_;
val result_;
};
// helper functions to create the expressions
template<class A>
derived_ptr<value_xpr<A>> input(const A &a) {
return derived_ptr<value_xpr<A>>(std::make_unique<value_xpr<A>>(a));
}
template<class A,class B>
derived_ptr<product_xpr<A,B>> operator*(expression_ptr<derived_ptr<A>> &&a, expression_ptr<derived_ptr<B>> &&b) {
return derived_ptr<product_xpr<A,B>>(std::make_unique<product_xpr<A,B>>(std::move(a).transfer_cast(), std::move(b).transfer_cast()));
}
template<class A>
derived_ptr<output_xpr<A>> eval(expression_ptr<derived_ptr<A>> &&a) {
return derived_ptr<output_xpr<A>>(std::make_unique<output_xpr<A>>(std::move(a).transfer_cast()));
}
int main() {
Eigen::MatrixXi mat(2, 2);
mat << 1, 1, 0, 1;
val one(mat), two(mat), three(mat);
auto xpr = eval(input(one) * input(two) * input(one) * input(two));
std::cout << xpr() << std::endl;
return 0;
}

Function object vs. function in a header-only library

I am writing a library that I would like to keep header-only. In the code I have something like this:
// Wrapper.h
#ifndef INCLUDED_WRAPPER_H
#define INCLUDED_WRAPPER_H
namespace quux {
template <typename T, typename U>
class Wrapper
{
T m_t;
U m_u;
public:
Wrapper(T const & t, U const & u) : m_t(t), m_u(u) { }
// ...
};
} // namespace quux
#endif // INCLUDED_WRAPPER_H
// Foo.h
#ifndef INCLUDED_FOO_H
#define INCLUDED_FOO_H
#include <type_traits>
#include "Wrapper.h"
namespace quux {
// if some type is special, then there will be a specialization of this
// struct derived from std::true_type
template <typename T> struct is_special : std::false_type { };
class Foo
{
template <typename T>
Wrapper<Foo, T> impl(T const & t, std::true_type ) const
{
return Wrapper<Foo, T>(*this, t);
}
template <typename T>
T const & impl(T const & t, std::false_type ) const;
{
return t;
}
public:
template <typename T>
auto operator()(T const & t) const // using automatic return type deduction
{
return impl(t, is_special<T>());
}
};
#if 1
Foo const foo;
#else
template <typename T>
auto foo(T const & t) // using automatic return type deduction
{
return Foo()(t);
}
#endif
} // namespace quux
#endif // INCLUDED_FOO_H
I see two different ways to have a callable entity with the name "quux::foo": a constant object named foo (the #if 1 - branch) or a function named foo that forwards its arguments to a Foo-object (the #else-branch). Which version should I prefer? A const Object has internal linkage so there are no linker errors if the header is included in multiple translation units. Are there any salient differences between the two approaches?
As you are calling a function, and your function object has no state, I would go with the function interface.
First, because functions can be overloaded, while function objects cannot outside of the body of the function object. You may wish to enable ADL extensions to your function.
Second because function objects are wierd. They cannot be converted to function pointers (in your case for no good reason), for example (note you can fix that with more boilerplate). Weird solutions are only a good idea when simple solutions are insufficient: in this case the simple perfect forwarding function is simpler.
Finally you might want to make your functions perfect forward, and have T&& rvalues give functions that return T at the outermost API level. This enables lifetime extension of temporaries to pass through your functions.

Resources