Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

VC++ error when using a pointer to a template function

I'm trying to write a template callback function for libcurl. However, when using a pointer to an instance of the template function, VC++ 2008 and 2010 keep giving me this error:

template-callback.cpp(27) : error C2664: 'curl_easy_setopt' : cannot convert parameter 3 from 'size_t (__cdecl *)(void *,size_t,size_t,void *)' to '...' Context does not allow for disambiguation of overloaded function

But GCC (4.5.1) compiles the code without a problem. This is a trimmed version of the code:

#include <string>

template<typename String>
size_t callback(
    void*       ptr
  , size_t  size
  , size_t  nmemb
  , void*       userdata
)
{
  //String* str = static_cast<String*>(userdata);
  size_t    len = size*nmemb;
  //str->append(static_cast<char const*>(ptr), len);
  return len;
}

typedef size_t (*write_callback)(void*, size_t, size_t, void*);
struct CURL;
enum CURLOption { none };
void curl_easy_setopt(CURL*, CURLOption, ...);

void f()
{
  CURL* curl = NULL;
  CURLOption option = none;

  // This gives an error
  curl_easy_setopt(curl, option, &callback<std::string>);

  // This doesn't
  write_callback cb = &callback<std::string>;
  curl_easy_setopt(curl, option, cb);
}

Is this a bug in VC++ or am I doing something wrong?

like image 491
Pablo Avatar asked May 27 '11 09:05

Pablo


1 Answers

I have reproduced the issue on ideone (C++03 with gcc-4.3.4):

#include <iostream>

typedef void (*FuncType)(int);

void foo(FuncType);
void bar(...);

template <typename T>
void callback(T t) { std::cout << t << "\n"; }

int main() {
  foo(&callback<int>); // OK
  bar(static_cast<FuncType>(&callback<int>)); // OK
  bar(&callback<int>); // error: address of overloaded function
                       // with no contextual type information
}

The issue seems to come from the interaction of the variadic argument and the function pointer.

Note: in C++0x mode with gcc-4.5.1 it works fine

I surmise that the issue comes from the overload resolution of bar (or curl_easy_setopt in your case).

The problem is that in order to use the ellipsis, the compiler as to decide how to pass the argument: int, double, pointer, ... It seems that it is unable to decide, by itself, what the type of &callback<int> is.

When we use foo, or perform a cast, it is unambiguous because there is no choice.

I suspect a conversion issue, but I don't have a version of the C++03 standard to dig into.

like image 79
Matthieu M. Avatar answered Nov 19 '22 11:11

Matthieu M.