Programmer585
Programmer585

Reputation: 93

Deduction template argument C++

Please, consider the code below:

template<typename T>
bool function1(T some_var) { return true; }

template <typename T>
bool (*function2())(T) {
  return function1<T>;
}

void function3( bool(*input_function)(char) ) {}

If I call

function3(function2<char>());

it is ok. But if I call

function3(function2());

compiler gives the error that it is not able to deduction the argument for template.

Could you, please, advise (give an idea) how to rewrite function1 and/or function2 (may be, fundamentally to rewrite using classes) to make it ok?

* Added *

I am trying to do something simple like lambda expressions in Boost.LambdaLib (may be, I am on a wrong way):

sort(some_vector.begin(), some_vector.end(), _1 < _2)

I did this:

template<typename T>
bool my_func_greater (const T& a, const T& b) {
  return a > b;
}

template<typename T>
bool my_func_lesser (const T& a, const T& b) {
  return b > a;
}

class my_comparing {
 public:
  int value;
  my_comparing(int value) : value(value) {}
  template <typename T>
  bool (*operator<(const my_comparing& another) const)(const T&, const T&) {
    if (this->value == 1 && another.value == 2) {
      return my_func_greater<T>;
    } else {
      return my_func_greater<T>;
    }
  }
};

const my_comparing& m_1 = my_comparing(1);
const my_comparing& m_2 = my_comparing(2);

It works:

sort(a, a + 5, m_1.operator< <int>(m_2));

But I want that it doesn't require template argument as in LambdaLib.

Upvotes: 6

Views: 450

Answers (4)

Jan Hudec
Jan Hudec

Reputation: 76276

Deduction from return type is not possible. So function2 can't be deduced from what return type you expect.

It is however possible to deduce cast operator. So you can replace function2 with a helper structure like: Unfortunately there is no standard syntax for declaring cast operator to function pointer without typedef and type deduction won't work through typedef. Following definition works in some compilers (works in G++ 4.5, does not work in VC++ 9):

struct function2 {
    template <typename T>
    (*operator bool())(T) {
        return function1<T>;
    }
};

(see also C++ Conversion operator for converting to function pointer).

The call should than still look the same.

Note: C++11 introduces alternative typedef syntax which can be templated. It would be like:

struct function2 {
    template <typename T>
    using ftype = bool(*)(T);

    template <typename T>
    operator ftype<T>() {
        return function1<T>;
    }
};

but I have neither G++ 4.7 nor VC++ 10 at hand, so I can't test whether it actually works.


Ad Added:

The trick in Boost.Lambda is that it does not return functions, but functors. And functors can be class templates. So you'd have:

template<typename T>
bool function1(T some_var) { return true; }

class function2 {
    template <typename T>
    bool operator()(T t) {
        function1<T>;
    }
};

template <typename F>
void function3( F input_function ) { ... input_function(something) ... }

Now you can write:

function3(function2);

and it's going to resolve the template inside function3. All STL takes functors as templates, so that's going to work with all STL.

However if don't want to have function3 as a template, there is still a way. Unlike function pointer, the std::function (C++11 only, use boost::function for older compilers) template can be constructed from any functor (which includes plain function pointers). So given the above, you can write:

void function3(std::function<bool ()(char)> input_function) { ... input_function(something) ... }

and now you can still call:

function3(function2());

The point is that std::function has a template constructor that internally generates a template wrapper and stores a pointer to it's method, which is than callable without further templates.

Upvotes: 5

Murali Krishna
Murali Krishna

Reputation: 311

I am not sure if this help you and I am not an expert on this. I have been watching this post since yesterday and I want to participate in this.

The template cannot deduce it's type because the compiler does not know what type you are expecting to return. Following is a simple example which is similar to your function2().

template<typename T>
T foo() {
    T t;
    return t;
};

call this function

foo(); // no type specified. T cannot be deduced.

Is it possible to move the template declaration to the class level as follows:

template<typename T>
bool my_func_greater (const T& a, const T& b) {
  return a > b;
}

template<typename T>
bool my_func_lesser (const T& a, const T& b) {
  return b > a;
}

template <typename T>
class my_comparing {
public:
    int value;
    my_comparing(int value) : value(value) {}
    bool (*operator<(const my_comparing& another) const)(const T&, const T&) {
        if (this->value == 1 && another.value == 2) {
            return my_func_greater<T>;
        } else {
            return my_func_greater<T>;
        }
    }
};

and declare m_1 and m_2 as below:

const my_comparing<int>& m_1 = my_comparing<int>(1);
const my_comparing<int>& m_2 = my_comparing<int>(2);

Now you can compare as follows:

if( m_1 < m_2 )
    cout << "m_1 is less than m_2" << endl;
else
    cout << "m_1 is greater than m_2" << endl;

I know this is simple and everyone knows this. As nobody posted this, I want to give a try.

Upvotes: 1

bitmask
bitmask

Reputation: 34628

After your edit, I think what you want to do can be done simpler. See the following type:

struct Cmp {
  bool const reverse;
  Cmp(bool reverse) : reverse(reverse) {}
  template <typename T> bool operator()(T a, T b) {
    return reverse != (a < b);
  }
};

Now, in your operator< you return an untyped Cmp instance depending on the order of your arguments, i.e. m_2 < m_1 would return Cmp(true) and m_1 < m_2 would return Cmp(false).

Since there is a templated operator() in place, the compiler will deduce the right function inside sort, not at your call to sort.

Upvotes: 2

Abyx
Abyx

Reputation: 12918

Compiler don't use context of expression to deduce its template parameters. For compiler, function3(function2()); looks as

auto tmp = function2();
function3(tmp);

And it don't know what function2 template parameter is.

Upvotes: 5

Related Questions