views:

1129

answers:

2

I have this code:

#include <iostream>
#include <functional>

struct A
{
    int operator()(int i) const {
        std::cout << "F: " << i << std::endl;
        return i + 1;
    }
};

int main()
{
    A a;
    std::tr1::function<int(int)> f = std::tr1::ref(a);
    std::cout << f(6) << std::endl;
}

The aim is to pass the functor object by a reference_wrapper, in a way to avoid useless copy costructor calls. I expect the following output:

F: 6
7

It works correctly with GCC >= 4.4.0, Visual Studio 2008 and with boost by substituting std::tr1 namespace with boost. It only doesn't work with the new Visual Studio 2010 both Express Beta 2 and Release Candidate.

Are this new C++ features bugged in vs2010? Or there is some mistake or misuse in the code?

+5  A: 

I think i found the reason. This is what TR1 3.4/2 says about result_of<T(A1, A2, ..., AN)>::type, used in the determination of the return type of reference_wrapper<T>::operator():

The implementation may determine the type member via any means that produces the exact type of the expression f(t1, t2, ..., tN) for the given types. [Note: The intent is that implementations are permitted to use special compiler hooks —end note]

And then paragraph 3:

If F is not a function object defined by the standard library, and if either the implementation cannot determine the type of the expression f(t1, t2, ..., tN) or if the expression is ill-formed, the implementation shall use the following process to determine the type member:

  • If F is a possibly cv-qualified class type with no member named result_type or if typename F::result_type is not a type:
    • If N=0 (no arguments), type is void.
    • If N>0, type is typename F::template result<F(T1, T2,..., TN)>::type

The error message is an artefact of trying these fall-backs. Provide a typedef for result_type to int and it should work, i think. Notice that in C++0x, this is different. It does not rely on result_type or a result template, since it can use decltype.

If with <functional> it fails with MSVC10 in C++0x mode, it smells like a bug, i would say. But maybe someone else knows what's going on. It may (but is not guaranteed to) work with <tr1/functional> in C++0x mode if that header chooses to take the decltype way instead of ::result_type. I would typedef result_type - that way i think it should always work regardless of whether the tr1 header is used or the c++0x header.


Also notice that boost::tr1 says in its documentation that it does not support the function call operator (but it merely supports implicit conversions to T&).

Johannes Schaub - litb
Yeah, this fix the problem :D It is a pity for vs2010 for this regression with respect to the previous 2008 version... Most recent draft strictly requires the compiler to be able to recognise the return type automatically.http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n3000.pdfParagraph 20.7.4
Dj Gaspa
A: 

I encounter a similar problem here : http://stackoverflow.com/questions/2216041/prevent-unnecessary-copies-of-c-functor-objects/2216928#2216928

To make it compile on MSVC10, I had to derive my function object from std::unary_function.

Thomas Petit