2015-10-30 15 views
26
template <int * ip> struct test {}; 

struct q { 
    static int a; 
    int b; 

    constexpr q(int b_) : b(b_) {} 
}; 

int i; 
constexpr q q0(2); 

int main() 
{ 
    constexpr test<&i> t1;  // Works fine 
    constexpr test<&q::a> t2; // Works 
    constexpr test<&q0.b> t3; // Does not work; address of non-static member? 

    return 0; 
} 

Khai báo t3 trong đoạn mã trên không thành công mặc dù đối số mẫu &q0.b được biết trong thời gian biên dịch. Một số googling tiết lộ rằng đây là không được phép theo tiêu chuẩn (phần 14.3.2):Tại sao địa chỉ của thành viên không tĩnh không được cho phép làm tham số không kiểu mẫu?

[Note: Addresses of array elements and names or addresses of non-static class members are not acceptable template-arguments.

X<&s.m> x4; // error: address of non-static membe

Vậy tại sao chính xác được này không được công nhận một cách rõ ràng theo tiêu chuẩn mặc dù các địa chỉ của các thành viên không tĩnh của biến toàn cục là độc đáo cũng như được biết đến trong thời gian biên dịch?

+0

Tôi đã thử điều này trên gcc 5.1.1 và clang 3.5.0 với -std = C++ 11 – nav

+0

Không có '(mới q) -> b' không được biết tại thời gian biên dịch –

+0

Đó là loại không phải là' int * ' , đó là 'int q :: *', phải không? – skypjack

Trả lời

15

Trước tiên, để sử dụng con trỏ/tham chiếu đến các đối tượng con, bạn cần phải có khả năng xé chúng. Đó là một công việc khá lớn.

Thứ hai, và có lẽ quan trọng hơn, từ N4198:

The restriction that the constant expression must name a complete object is retained to avoid aliasing problems with pointers to subobjects:

struct A { int x, y; } a; 
template<int*> struct Z; 
using B = Z<&a.x + 1>; 
using C = Z<&a.y>; 
// Are B and C the same type? 

Để báo Richard Smith,

The answer "yes" is problematic because there are things you can do with a pointer to [ a.y ] that would have undefined behavior if performed on a pointer past the end of [ a.x ] The answer "no" is problematic because they (in typical implementations) represent the same address.

+0

+, yếu tố chính trong một nutshell. – Columbo

+1

@ T.C. Chúng ta sẽ không chạy vào cùng một tình huống có x và y là các thành viên tĩnh hay các biến toàn cầu đơn giản?(Tôi không phải là chuyên gia trong C++; Tôi chỉ đang cố hiểu :)) – nav

+0

@ T.C. Trích dẫn của bạn từ Richard Smith dường như đưa ra một lý lẽ hợp lý hơn: "Hãy nhớ rằng các tham số mẫu phải là một thứ có thể được xác định hợp lý tại thời gian biên dịch và có thể bị xáo trộn. mọi thứ xung quanh) và không nhất thiết phải có các quy tắc rõ ràng về cách thức chúng bị xáo trộn trên tất cả các nền tảng. " – Thinkeye

1

Thay thế chính của bạn với đoạn mã này

int main(void) 
{  
constexpr static int bb = 5;  
constexpr test<&bb> t;  
return 0; 
} 

và bạn sẽ nhận được lỗi bb không thể được sử dụng như là một đối số mẫu bec sử dụng nó không có liên kết (không bị nhầm lẫn với nhân viên liên quan đến trình liên kết).

Không thể truy cập thành viên dữ liệu lớp trừ khi chúng được tham chiếu qua đối tượng và không thể được xem xét trong quá trình tạo mẫu, vì thành viên dữ liệu không có liên kết, nghĩa là chúng không được xác định biểu tượng và do đó không thể được sử dụng làm đối số mẫu .

Điều đó đang được nói, làm một readelf bạn có thể xác minh điều này:

48: 00000000004006ac  4 OBJECT LOCAL DEFAULT 14 q0 


68: 000000000060097c  0 NOTYPE GLOBAL DEFAULT ABS __bss_start 
69: 0000000000600978  4 OBJECT GLOBAL DEFAULT 23 q::a 

nhưng không có q0.b xác định. Cách thay thế sẽ là đặt tên (mangle) không có thành viên lớp tĩnh nào có khả năng phân chia năng động của ngôn ngữ.

Các vấn đề liên quan