cexplorer
cexplorer

Reputation: 557

Compilation error with adaptable function objects in c++

I am learning how to use standard generic algorithms in c++. In the below code example I am trying to convert strings to double with the help of a custom compose function that combines two operations (string to const char* and const char* to double) into one.

I have written unary_composer as a adaptable function object.

However when i compile it, i am getting below error

Error 2 error C2664: 'double unary_composer::operator ()(const std::basic_string<_Elem,_Traits,_Ax> *)' : cannot convert parameter 1 from 'std::basic_string<_Elem,_Traits,_Ax>' to 'const std::basic_string<_Elem,_Traits,_Ax> *

'

using namespace std;

template<typename F1, typename F2>
class unary_composer : public unary_function<typename F2::argument_type, typename F1::result_type>
{
    F1 f1;
    F2 f2;

public:
unary_composer(F1 lf1, F2 lf2) : f1(lf1), f2(lf2){}

typename F1::result_type operator()(typename F2::argument_type x)
{
   return f1(f2(x));
}

};

template <typename F1, typename F2>
unary_composer<F1, F2> compose(F1 fone, F2 ftwo)
{
   return unary_composer<F1, F2>(fone, ftwo);
}

int _tmain(int argc, _TCHAR* argv[])
{
   const int SZ = 9;
   vector<string> vs(SZ);

   srand(time(0));

   generate(vs.begin(), vs.end(), NumGenerator()); // Generates strings with random digits ex: "12.35". NumGenerator is defined in another source file.

   vector<double> vd;

   // Transform the strings to doubles
   transform(vs.begin(), vs.end(), back_inserter(vd), compose(ptr_fun(atof), mem_fn(&string::c_str)));

   copy(vd.begin(), vd.end(), ostream_iterator<double>(cout, " ")); // print to console
   cout<<endl;

   return 0;
}

When I use mem_fun_ref in place of mem_fn, it works fine. Perhaps, the error says unary_composer's opeartor function is expecting argument of type const string* but string is getting passed. but i don't know how to fix it. Where am I missing ?

PS: The example is taken from Thinking in C++ vol2 (chapt 6)

Upvotes: 0

Views: 106

Answers (1)

juanchopanza
juanchopanza

Reputation: 227418

std::mem_fn's argument_type is pointer to the type, which breaks your unary_composer which uses it as its own argument_type.

Depending on the level of C++11 support in your compiler, you could change the composer to something along the lines of

template<typename F1, typename F2>
class unary_composer
{
    F1 f1;
    F2 f2;

public:
    unary_composer(F1 lf1, F2 lf2) : f1(lf1), f2(lf2){}

    template <typename ARG>
    auto operator()(ARG x)->decltype(f1(f2(x))
    {
        return f1(f2(x));
    }
};

and invoke it like this:

transform(vs.begin(), vs.end(), back_inserter(vd),
          compose(std::atof, mem_fn(&string::c_str)));

See a working example.

For completeness, here's a version that does not require you to roll out any functors:

transform(vs.begin(), vs.end(), back_inserter(vd),
         [](const std::string& s)
         {return std::stod(s);});

Note that mem_fun, mem_fun_ref, unary_functor and others are deprecated since C++11 and will most likely be removed in C++17.

Upvotes: 1

Related Questions