使用函数指针作为参数,模板参数推断失败

时间:2016-07-11 17:05:42

标签: c++ templates visual-studio-2012

我写了很多模板化的函数。例如:

template <typename T>
inline int Foo(T* t, unsigned char** p, size_t* size, size_t (*MyHandler)(T*))
{
    ...
}

template <>
inline int Foo<Bar>(Bar* t, unsigned char** p, size_t* size, size_t (*MyHandler)(Bar*))
{
    ...
}

如果我使用显式模板参数调用这些函数,那么一切运行良好,i.E。

Foo<Bar>(&myBar, pBuffer, size, FooFoo<Bar>);

FooFoo<T>是一个不同的模板化函数

如果用户不需要跟踪类型,那将是非常有利的。所以我想使用以下语法:

Foo(&myBar, pBuffer, size, FooFoo);

然而,这一行引起了一对

  • C2784:无法从'Bar *'
  • 推断出'T *'的模板参数
  • C2796:不能使用函数模板'size_t FooFoo(T *)作为函数参数

Foo一样,存在专门化FooFoo<Bar>

据我所知,由于第一个参数类型为T*,因此应该可以推导出T,或者该函数指针是否与推论相混淆?

任何提示都将不胜感激。

更新3 根据请求的MCVS,@ Yakk建议的更改最终有效!

#include <stdio.h>

struct Bar
{
    int a;
    int b;
    int c;
};


template<class T>struct id_t{typedef T type;}; 

template <typename T>
inline size_t FooFoo(T* t)
{
    printf("FooFoo calculating size of T...\r\n", sizeof(T));
    return sizeof(T);
}

template <>
inline size_t FooFoo<Bar>(Bar* t)
{
    printf("FooFoo calculating size of Bar...\r\n", sizeof(Bar));
    return sizeof(Bar);
}

template <typename T>
inline int Foo(T* t, unsigned char** p, size_t* size, typename id_t<size_t (*)(T*)>::type MyHandler)
{
    printf("Foo telling size of T: %u\r\n", MyHandler(t));
    return 0;
}

template <>
inline int Foo<Bar>(Bar* t, unsigned char** p, size_t* size, typename id_t<size_t (*)(Bar*)>::type MyHandler)
{
    printf("Foo telling size of Bar: %u\r\n", MyHandler(t));
    return 0;
}



int main(int argc, char* argv[])
{
    int i;
    Bar myBar;

    Foo<Bar>(&myBar, nullptr, 0, FooFoo<Bar>); //  works
    Foo<int>(&i, nullptr, 0, FooFoo<int>); // works

    Foo(&myBar, nullptr, 0, FooFoo<Bar>); //  works
    Foo(&i, nullptr, 0, FooFoo<int>); // works


    Foo(&myBar, nullptr, 0, FooFoo);    // error C2896: 'int Foo(T *,unsigned char **,size_t *,size_t (__cdecl *)(T *))' : cannot use function template 'size_t FooFoo(T *)' as a function argument
                                        // error C2784: 'int Foo(T *,unsigned char **,size_t *,size_t (__cdecl *)(T *))' : could not deduce template argument for 'T *' from 'Bar *'

    Foo(&i, nullptr, 0, FooFoo);        // error C2896: 'int Foo(T *,unsigned char **,size_t *,size_t (__cdecl *)(T *))' : cannot use function template 'size_t FooFoo(T *)' as a function argument
                                        //error C2784: 'int Foo(T *,unsigned char **,size_t *,size_t (__cdecl *)(T *))' : could not deduce template argument for 'T *' from 'int *'

    return 0;
}

非常感谢!

2 个答案:

答案 0 :(得分:2)

所有参数在推导时具有相同的权重,并且是独立推导的。要阻止使用特定参数进行演绎,请执行以下操作:

PrimitiveValue

现在点template<class T>struct id_t{typedef T type;}; template<class T>using block_deduction=typename id_t<T>::type; 并制作它:

size_t (*MyHandler)(T*)

或者在非C ++ 11编译器中:

block_deduction<size_t (*)(T*)> MyHandler

这样做是将typename id_t<size_t (*)(T*)>::type MyHandler 参数的类型放入非推导的上下文中。因此,编译器不会尝试,而是使用第一个参数的推导来确定MyHandler。然后生成T的类型。然后,您传递的重载集将根据签名进行解析,一切正常(可能)。

答案 1 :(得分:1)

您的问题不是T=Bar Foo的扣除 - 它是FooFoo的扣除。