将函数用作非类型模板参数时出错

时间:2010-02-03 20:07:12

标签: c++ function templates parameters

我有这个模板:

        template <class SourceFormat, class DestFormat, void (*convert)(DestFormat, SourceFormat)>
    static void _draw(...);

这些功能:

    template <class Class1, class Class2>
    inline static void convertNone(Class1& dest, Class2& source) {
        dest = source;
    };
    inline static void convertARGB_GREY(unsigned __int32& dest, unsigned __int8& source) {
        dest = source + (source << 8);
        dest += (dest << 16);
    };

我在另一个函数中使用该模板:

    void Blitter::draw(...) {

    if (...) {
        _draw<unsigned __int32, unsigned __int32, &convertNone>(...);
    } else {
        _draw<unsigned __int32, unsigned __int8, &convertARGB_GREY>(...); // ERRORS go here!
    }
}

我收到这些错误:

Error   1   error C2440: 'specialization' : cannot convert from 'void (__cdecl *)(unsigned int &,unsigned char &)' to 'void (__cdecl *const )(unsigned char,unsigned int)'  d:\projects\fanlib\source\blitter.cpp   102
Error   2   error C2973: 'FANLib::Blitter::_draw' : invalid template argument 'void (__cdecl *)(unsigned int &,unsigned char &)'    d:\projects\fanlib\source\blitter.cpp   102

我认为很明显我不完全理解函数 - 参数......: - (

非常感谢提前

2 个答案:

答案 0 :(得分:5)

您的代码中存在多个问题。

在您的代码中,当您致电_draw时,SourceFormat模板的DestFormat_draw参数会提供显式参数。这些参数是普通的非引用整数类型。这自动意味着_draw的第三个模板参数应该是一个按值获取其参数的函数。即如果SourceFormatDestFormatunsigned __int32,则函数指针应具有类型void (*)(unsigned __int32, unsigned __int32)。相反,您正在尝试提供一个通过引用获取其参数的函数,即指针类型为void (*)(unsigned __int32 &, unsigned __int32 &)。这些是完全没有实现和不兼容的指针类型。由于同样的原因,以下简单代码无法编译

void foo(int&);
void (*pf)(int) = foo; 
// ERROR: a value of type "void (*)(int &)" cannot be used to initialize an entity of type "void (*)(int)"

您认为这是如何工作的?从实际函数参数中删除引用(改为使用返回类型),或者在模板参数声明中添加它们。

另一个问题是您正在尝试使用指针static函数(内部链接)来参数化模板。这在C ++中是非法的。说明问题的简短示例可能如下所示

template <void (*P)()> void foo() {}
static void bar() {}
...
foo<bar>();
// ERROR: template argument may not reference a non-external entity

如果要使用指针值对模板进行参数化,则您提供的参数必须指向具有外部链接的实体。您的编译器可能允许您按原样执行的操作,但它仍然是非法的。

最后,用C ++结束带分号的独立函数定义是非法的。实际上它被视为“空声明”,并且在C ++中没有“空声明”。许多编译器允许这样做,但它仍然是非法的。

P.S。此外,正如其他人已经指出的那样,您设法在非模板转换器函数convertARGB_GREY中反转参数类型的顺序。

答案 1 :(得分:2)

我不知道你是否故意这样做,但你的模板参数是Source / Destintaion然后是Destination / Source。

请注意,当您执行_draw<unsigned __int32, unsigned __int8, &convertARGB_GREY>(...);时,您的模板定义会将其填入:

SourceFormat = unsigned __int32
DestFormat = unsigned __int8
void (*convert)(unsigned __int8, unsigned __int32)

你没有这个定义的功能。

你确实有匹配的 void (*convert)(unsigned __int32&, unsigned __int8&)
你看到参数不匹配吗?

声明你的模板:

template <
    class SourceFormat,
    class DestFormat,
    void (*convert)(SourceFormat, DestFormat)> 
static void _draw(...);

和你的函数声明如下:

void convertARGB_GREY(
    unsigned __int32 source,        // notice how I removed the '&'
    unsigned __int8 destination)    // character on these two lines

它将编译。 (由于您丢失了引用,我建议在这种情况下返回结果:unsigned __int8 destination convertARGB_GREY(...)尽管如此。)