【问题标题】:C++11: (recursive) pointer arithmetic in templates (TMP)C++11:模板中的(递归)指针算法(TMP)
【发布时间】:2014-10-27 07:40:42
【问题描述】:

不要问我为什么,但我试图在编译时初始化一个指针数组(指针指向另一个静态数组的元素)。这涉及 TMP,因此在构建可变参数列表时需要模板递归。我已将问题缩小到以下几点:

template <int const * const P>
struct Foo
{
    constexpr static int const * const bar = P;
};

constexpr int const array[5] = {0, 1, 2, 3, 4}; // global, so has linkage

int main()
{
    /* 1 */ cout << *Foo<array>::bar << '\n';
    /* 2 */ cout << *Foo<array + 1>::bar << '\n';
    /* 3 */ cout << *Foo<&array[1]>::bar << '\n';
}

案例 1 工作正常,并打印 '0'。

案例 2 无法编译,GCC (4.9.1) 报错:

error: ‘(((const int*)(& array)) + 4u)’ is not a valid template argument for ‘const int*’ because it is not the address of a variable
 cout << *Foo<array + 1>::bar << '\n';
                       ^

案例 3 无法编译,GCC 报错:

error: template argument 1 is invalid
 cout << *Foo<&array[1]>::bar << '\n';

我主要关心案例2。为什么不能做常量指针算术并将结果传递给模板?

【问题讨论】:

    标签: c++ templates pointers c++11 metaprogramming


    【解决方案1】:

    你说得对,当指定指针类型的非类型模板参数时,不可能进行任何指针算术。标准如此明确地说,C++11 14.3.2/1:

    用于非类型、非模板的 模板参数 模板参数 应为以下之一:

    • ...
    • 一个常量表达式 (5.19),它指定具有静态存储持续时间的对象的地址,并且 外部或内部链接或具有外部或内部链接的功能,包括功能模板 和函数模板 ID,但不包括非静态类成员,表示(忽略括号)为 &amp; id-expression, 除了 &amp; 可以省略,如果名称指的是一个函数或数组,应该 如果对应的 template-parameter 是引用,则省略;或
    • ...

    (强调我的,省略了此处不适用的其他要点)。

    为了完整起见,id-expression 在 5.1.1 中定义为限定或非限定标识符、操作符名称、析构函数名称或模板标识符。 [] 不允许在那里。

    【讨论】:

    • 哇,谢谢,真快。好吧,如果标准是这样说的……但是您知道为什么吗?我的意思是......如果标准允许简单的指针算术,会发生什么样的可怕事情?
    • @JorenHeit 抱歉,我还没有考虑过。这样的反例通常是很邪恶的,所以即使我想不出结果,知道一三个也不会让我感到惊讶。
    猜你喜欢
    • 2018-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-10
    • 1970-01-01
    • 1970-01-01
    • 2011-04-01
    相关资源
    最近更新 更多