template<typename U, typename T, typename binary_functor>
struct template_param_swap
{
  binary_functor<U, T> func1; #1
  binary_functor<T, U> fun2; #2
};

CH3 of modern c++ design may solve this, but I am not a template
wizard and don't have the ability to make it yet.
template template parameter could make #1 become possible
but not #2
How could I make this become possible?Thanks

Recommended Answers

All 7 Replies

I come up a solution, weird but work.

template<typename U, typename T, template<typename, typename> class binary_functor_1>
struct template_param_swap
{
  template<typename J, typename K>
  struct func2_wrap
  {
    binary_functor_1<K, J> func1;
    binary_functor_1<J, K> func2;
  };
  func2_wrap<T, U> func;
};

I try to think of this kind of template class because of the post at http://www.daniweb.com/software-development/cpp/threads/390889
I don't want to pass in two functors into my own "set_difference"
Do you have better solutions?Thanks

Usually, I don't like template template parameters, because of the weirdness associated with them (both in implementing the class template that receives the parameter as well as in using it). I usually prefer to go the route of meta-factory types instead.

Consider this meta-factory:

template <typename FactoryTag, typename T, typename U>
struct binary_functor {
  BOOST_STATIC_ASSERT(false,"General binary_functor template is invalid!");
};

Then, if you want to create, say, a less-than functor, you could simply do this:

template <typename T, typename U>
struct less_than : public std::binary_function<T,U,bool> {
  bool operator()(const T& a, const U& b) const { 
    return a < b; 
  };
};

//first create a meta-factory tag:
struct less_than_tag { };

//and then, specialize the meta-factory for that tag:
template <typename T, typename U>
struct binary_functor< less_than_tag, T, U> {
  typedef less_than<T,U> type;
};

And now, your template-param-swap thing can be implemented as:

template<typename U, typename T, typename FunctorTag>
struct template_param_swap
{
  typename binary_functor<FunctorTag, U, T>::type func1; #1
  typename binary_functor<FunctorTag, T, U>::type fun2; #2
};

The syntax is not necessarily much nicer, but the above is a solution that tends to scale much better and be able to tailor more easily to different situations via either partial specializations of the meta-factory or different ways in which to compute the functor types.

One way is for the binary function to also provides a metafunction rebind a la allocators.

template< typename T, typename U > struct my_fun // TODO: std::enable_if for std::is_integral
{
    bool operator() ( const T& a, const U& b ) const { return b != 0 && a%b == 0 ; }
    template< typename X, typename Y > struct rebind
    {
        typedef my_fun<X,Y> type ;
    };
};

template < typename T, typename U, typename FN > bool foo( const T& a, const U& b, FN fn )
{
    auto fn2 = typename FN::template rebind<U,T>::type() ;
    return fn(a,b) && fn2(a,b) ;
}

It is also a more generic mechanism; one is not restricted to just rebinding from <T,U> to <U,T>.

You guys are amazing
Both of your answers are pretty interesting

Is it possible to make it support the lambda expression of c++11?
Thank you very much

Sorry, I should specify it clearly
could I make lambda expression play the trick like above?
so I don't have to write another functor for small cases
Thanks

I don't understand where the lambda-expression would come into play. If you mean replacing the functor with a lambda-expression that could accept different parameter types, then you can't really do that because lambda-expressions cannot be templated, because lambda-expressions are expressions, they don't declare a type. They actually evaluate to a temporary callable object of a unnamed class type, in other words, creating a lambda expression is analogous to this (if you neglect the fact that lambdas are temporary and you neglect the practical problem with using local classes as functors):

int main() {
  std::vector<int> v; 
  //fill v with values.

  //sort with a lambda-expression:
  std::sort(v.begin(), v.end(), [](int a, int b) -> bool { return a < b; });

  //or, create a local functor object:
  struct {
    bool operator()(int a, int b) { return a < b; };
  } foo;
  //sort with that local functor (note, this is not actually legal in C++):
  std::sort(v.begin(), v.end(), foo);

  return 0;
};

The problem is although you could give "foo" templated / overloaded call operators to allow for different parameters (although you would need to bring it outside the function). You cannot do the same with the lambda-expression because it was designed to directly translate to the above analogy, without the possibility of providing multiple alternative overloads. I don't know if that was ever debated or considered as a possible addition to lambda-expressions, but considering that lambdas are mostly syntactic sugar, it would seem like complexifying its syntax to allow for more complex use-cases would kind-of work against its original purpose. In other words, be happy with using functors instead, lambdas are mostly for simple cases.

> could I make lambda expression play the trick like above?
> so I don't have to write another functor for small cases

Boost Phoenix has polymorphic lambdas.
And once there are polymorphic lambdas with support for lazy evaluation, no extra boiler plate is required:

#include <string>
#include <iostream>
#include <boost/phoenix/core.hpp>

template< typename T, typename U, typename FN > bool foo( T a, U b, FN fn )
{ return fn(a,b) <= fn(b,a) ; }

int main()
{
    using namespace boost::phoenix::arg_names ;

    auto plus = arg1 + arg2 ; // polymorphic lambda

    int i = 7, j = 9 ;
    double d = 3.456 ;
    std::string a = "abc", b = "defghijk" ;

    std::cout << plus(i,j) << ' ' << plus(i,d) << ' ' << plus(a,b) << '\n' ;

    std::cout << std::boolalpha << foo( i, d, plus ) << '\n' ;
}

C++ lamda expressions are monomorphic (polymorphic lambdas would have given more flexibility and expressive power). AFAIK, it was concepts that required lambdas to be monomorphic. With concepts, a constrained template should be able to use only other similarly constrained templates; asking for concept checks with lazy evaluation of constraints (which polymorphic lambdas would require) would have made the life of compiler writers extremely difficult. Concepts were eventually dropped, and supporting polymorphic lambdas in the absence of concepts would have been a fairly straightforward matter; however the clear intent is to definitely have concepts in the next standard ("in maybe five years" - Stroustrup).


BTW, this is valid C++

#include <algorithm>
#include <vector>

int main()
{
      std::vector<int> seq = { 1, 4, 3, 2 } ;
      struct foo { bool operator() ( int a, int b ) const  { return a < b ; } } ;
      std::sort( seq.begin(), seq.end(), foo() ) ; // this was not allowed in old C++
}
commented: great info! +14
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.