2

I know there was already Default value on generic predicate as argument.

But maybe there are new options now with c++11, c++14, or c++17?

How can i make this work without overload?

#include <vector> #include <numeric> #include <algorithm> #include <iterator> #include <iostream> #if 0 template <typename CONTAINER, typename PRED> void print(CONTAINER const & cont, PRED pred = [] (typename CONTAINER::value_type) { return true;}) { std::copy_if(cont.begin(), cont.end(), std::ostream_iterator<typename CONTAINER::value_type>(std::cout, " "), pred); std::cout << std::endl; } #else template <typename CONTAINER, typename PRED> void print(CONTAINER const & cont, PRED pred) { std::copy_if(cont.begin(), cont.end(), std::ostream_iterator<typename CONTAINER::value_type>(std::cout, " "), pred); std::cout << std::endl; } template <typename CONTAINER> void print (CONTAINER const & cont) { std::copy(cont.begin(), cont.end(), std::ostream_iterator<typename CONTAINER::value_type>(std::cout, " ")); std::cout << std::endl; } #endif bool even( const int& i) { return not (i % 2); } int main( int argc, char **argv) { std::vector<int> myVec(20); std::iota(myVec.begin(), myVec.end(), 1); print(myVec); print(myVec, even); return 0; } 

Enabling #if 0 section results in
../main.cpp:17:6: note: template argument deduction/substitution failed:
../main.cpp:56:13: note: couldn't deduce template parameter ‘PRED’

2
  • I don't know how to avoid the overload, but you could have single-parameter print call two-parameter print, and thus avoid duplicating the logic. Commented Aug 8, 2020 at 18:20
  • This would be an option. But i am looking for a base/generic type for the predicate to do w/o template parameter. Commented Aug 8, 2020 at 18:28

3 Answers 3

2

This may not be particularly helpful to you now, but you can make it work in C++20. There were several changes in the standard surrounding lambdas. In particular, lambdas can appear in unevaluated operands and template arguments, and capture-less lambdas are default constructible. So putting it to use we can simply write

template <typename CONTAINER, typename PRED = decltype([] (typename CONTAINER::value_type) { return true;})> void print(CONTAINER const & cont, PRED pred = {}) { std::copy_if(cont.begin(), cont.end(), std::ostream_iterator<typename CONTAINER::value_type>(std::cout, " "), pred); std::cout << std::endl; } 
Sign up to request clarification or add additional context in comments.

Comments

2

Something like this, perhaps:

template <typename CONTAINER> void print(CONTAINER const & cont, std::function<bool(typename CONTAINER::value_type)> pred = [] (typename CONTAINER::value_type) { return true;}) { std::copy_if(cont.begin(), cont.end(), std::ostream_iterator<typename CONTAINER::value_type>(std::cout, " "), pred); std::cout << std::endl; } 

Demo. Not particularly efficient, but it does appear to satisfy your requirements.

2 Comments

thanks! - this is what i was originally looking for. But you're right it always calls the more specific std::copy_if()
The inefficiency is not in copy_if, it's in std::function. Type erasure requires a heap allocation and virtual function calls, whereas in the original template-based formulation the predicate would most likely get inlined.
0

Igor proposed one - which is closer to what i intended originally (thanks!)
Here's another one:

#include <vector> #include <numeric> #include <algorithm> #include <iterator> #include <iostream> template <typename CONTAINER, typename...OPT_PRED> void print( CONTAINER const & cont, OPT_PRED... optPred) { if constexpr(sizeof...(OPT_PRED) == 1) { std::copy_if(cont.begin(), cont.end(), std::ostream_iterator<typename CONTAINER::value_type>(std::cout, " "), std::forward<OPT_PRED>(optPred)...); } else if constexpr(sizeof...(OPT_PRED) == 0) { std::copy(cont.begin(), cont.end(), std::ostream_iterator<typename CONTAINER::value_type>(std::cout, " ")); } else { static_assert(sizeof...(OPT_PRED) < 0 or sizeof...(OPT_PRED) > 1, "invalid number of arguments for print()"); } std::cout << std::endl; } bool even( const int& i) { return not (i % 2); } int main( int argc, char **argv) { std::vector<int> myVec(20); std::iota(myVec.begin(), myVec.end(), 1); print(myVec); print(myVec, even); return 0; } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.