无法将指针传递给const数据作为函数模板参数

时间:2013-02-21 22:19:49

标签: c++ templates

我有一个函数,它将函数指针作为参数,然后使用自己的参数调用该函数:

typedef int (*my_func_ptr)( int );

int foo( my_func_ptr f ) {
    static int i = 0;
    return i = f( i );
}

有时候,我需要将函数传递给foo,这些函数不仅仅依赖于整数输入来吐出结果。

int add_strlen( int i, const char* s ) {
    return i + strlen( s );
}

我可以重做上面的代码来使用std::function然后使用std::bind,但我最好在编译时创建这些函数,所以我使用模板。< / p>

template<const char* S>
int add_strlen( int i ) {
    return i + strlen( S );
}

/**
 * Usage:
 * char bar[] = "bar";
 * foo( add_strlen<bar> );
 */

使用指针作为模板参数时出现问题。每当我使用指向任何类型的常量数据的指针作为模板参数时,如果传递的参数被声明为该类型的非const数组,它只会设法编译。

char char_array[]             = "works";
const char const_char_array[] = "error";
char *char_ptr                = "error";
const char *const_char_ptr    = "error";

Clang中的相关错误(版本3.0-6)(char_ptrconst_char_ptr的错误相同):

func_ptr.cpp:29:9: error: no matching function for call to 'foo'
        foo( add_strlen<const_char_array> );
        ^~~
func_ptr.cpp:6:5: note: candidate function not viable: no overload of 'add_strlen' matching 'my_func_ptr' (aka 'int (*)(int)') for 1st argument
int foo( my_func_ptr f )

任何人都可以向我解释为什么会这样吗?我看到它的方式,模板参数S应该是const char*类型,在任何其他情况下,我可以传入任何const或非const指针或类型{{1}的数组并希望它能够发挥作用。我希望能够将我的数组声明为char,因为我甚至不想暗示它们是在运行时被修改的。有没有办法让我的数组const 将它们用作模板参数?

编辑:感谢一些帮助(以及更好的错误的Clang的更新版本),我能够确定提供带有内部链接的模板参数是问题的一部分。通过将上述变量声明为extern,我可以毫无错误地使用const。我还创建了一个简化的测试用例。它包括在下面:


add_strlen<const_char_array>

1 个答案:

答案 0 :(得分:1)

该错误似乎与您的身份以及您不允许将其用作非类型模板参数有关,请参考IBM Linux Compilers documentation for Non-type template parameters他们这样说:

  

非类型模板参数的语法与以下类型之一的声明相同:

     
      
  • 整数或枚举
  •   
  • 指向对象的指针或指向函数的指针
  •   
  • 对象的引用或对函数的引用
  •   
  • 指向成员的指针
  •   

char_array[]const_char_array[]在传入时的工作原因是因为它们在编译时是常量,并且在程序运行时永远不会在程序下面发生变化。可以传入积分类型,但不能传入指向整数类型的指针。

模板期望const char * a.k.a const char[x]的类型,但它也期望永远不会改变的东西,因此指针指向的位置可能永远不会改变。在编译器时间传入时,const_char_array传递char[6](“错误”)。该位置永远不会改变,内容永远不会改变。但是当传入const_char_ptr时它会得到一个const char *,而指针本身可能永远不会改变,它指向的位置完全可能会改变。它本身并不是一成不变的。

char *_arr = new char[20];
const char* _ptr_arr = _arr;

我们在此同意我的_ptr_arr与您的const_char_ptr的类型完全相同,但内容存储的位置可能会在运行时更改。在不允许的模板中,因为它可能需要模板的全新实例化,并且在创建模板时是不确定的。 char [6]是静态的,不会改变。

foo( add_strlen<_ptr_arr> );

导致以下编译器错误:

test.cpp:36:5: error: no matching function for call to 'foo'
    foo( add_strlen<_ptr_arr>);
    ^~~
test.cpp:6:5: note: candidate function not viable: no overload of 'add_strlen' matching 'my_func_ptr' (aka 'int (*)(int)') for 1st argument
int foo( my_func_ptr f ) {
    ^

哪个不是很有帮助,我们想弄清楚为什么没有有效的重载,用函数独立编译代码而不作为函数指针传递我们得到以下内容:

add_strlen<_ptr_arr>(0);

将导致:

test.cpp:36:5: error: no matching function for call to 'add_strlen'
    add_strlen<_ptr_arr>(0);
    ^~~~~~~~~~~~~~~~~~~~
test.cpp:16:5: note: candidate template ignored: invalid explicitly-specified argument for template parameter 'S'
int add_strlen( int i ) {
    ^

因此显式指定的参数无效,具体而言,我们无法传入指向积分的指针。