首页 文章

无效指针作为C中的模板参数

提问于
浏览
10

以下内容无法编译:

template<void *p>
class X {
// ...
};

int r;

int main()
{
    X<&r> x;

    return 0;
}

错误消息是

x.cc:10:6:错误:无法将模板参数'&r'转换为'void *'

显式地转换&r到(void *)也无济于事 . 错误消息变为:

x.cc:10:14:错误:无法将模板参数'(void *)(&r)'转换为'void *'

标准的哪一部分指明了这种行为? GCC版本是 gcc version 5.2.1 20151003 (Ubuntu 5.2.1-21ubuntu2)

Edit:

请注意使用例如int *而不是void *按预期工作 .

Edit: (answering myself)

当指定-std = c 1z时, notgcc HEAD 6.0.0 20151016 (experimental) 一起工作,既没有隐式也没有显式转换为"void *" .

doesclang HEAD 3.8.0 (trunk 250513) 一起工作,并且自从(至少) clang 3.6.0 (tags/RELEASE_360/final) 指定--std = c 1z并明确地转换为* void *“时 . 在没有显式强制转换的情况下,clang抱怨如下:

x.cc:10:7:错误:转换后的常量表达式中不允许从'int *'转换为'void *'

负责修复c语言规范中的这个bug是N4268,clang已经实现了 .

2 回答

  • 0

    通常,任何指向 void* 的指针都允许转换 .

    [C 11,4.10 / 2]类型为“指向cv T的指针”的prvalue,其中T是对象类型,可以转换为类型为“指向cv void的指针”的prvalue . 将“指向cv T的指针”转换为“指向cv void的指针”的结果指向T类型的对象所在的存储位置的开始,就好像该对象是类型T的最派生对象(1.8) (即,不是基类子对象) . 空指针值将转换为目标类型的空指针值 .

    但是,对于非类型模板参数,指定了某些转换:

    [C 11,14.3.2 / 5]对用作非类型模板参数的每个表达式执行以下转换 . 如果非类型模板参数无法转换为相应模板参数的类型,则程序格式错误 . [...] - 对于指向对象的类型指针的非类型模板参数,应用限定转换(4.4)和数组到指针转换(4.2);如果template-argument的类型为std :: nullptr_t,则应用空指针转换(4.10) . [...]

    由于省略,我们可以推断这种转换是不允许的 .

  • 1

    我不能引用你的章节和经文来引起我的兴趣(编辑是受欢迎的),但你想要做的是不允许在c .

    必须在编译时知道模板参数 . 指针仅在链接时解析,除非:

    • 在模板参数列表中使用 = nullptr 默认它们 .

    • 它们是成员函数指针(在编译时是已知的,因为它们仅仅是偏移量) .

    例如,这将编译:

    template<void * = nullptr>
    class X {
        // ...
    };
    
    int r;
    
    int main()
    {
        X<nullptr> x;
    
        return 0;
    }
    

相关问题