2015-03-04 24 views
7

Theo: constexpr static data member giving undefined reference error thành viên lớp constexpr tĩnh phải đáp ứng hai yêu cầu:khởi thống nhất tĩnh thành viên constexpr

template <typename Tp> 
struct wrapper { 
    static constexpr Tp value{}; // 1 
}; 

template<typename Tp> 
constexpr Tp wrapper<Tp>::value; // 2 

struct foo { 
}; 

int main() { 
    auto const& x = wrapper<foo>::value; 
    (void)x;  
} 
  1. Khởi tạo bên trong định nghĩa lớp (vì nó là constexpr)
  2. Defined ngoài định nghĩa lớp (vì nó là tĩnh)

Nếu tôi thay đổi 1. thành đồng nhất initiali zation

template <typename Tp> 
struct wrapper { 
    static constexpr auto value = Tp{}; // uniform initialization 
}; 

template<typename Tp> 
constexpr Tp wrapper<Tp>::value; 

biên dịch phàn nàn tờ khai về mâu thuẫn:

$ g++ prog.cc -Wall -Wextra -std=c++1z -pedantic 
prog.cc:7:31: error: conflicting declaration 'constexpr const Tp wrapper<Tp>::value' constexpr Tp wrapper<Tp>::value; 
prog.cc:3:29: note: previous declaration as 'constexpr const auto wrapper<Tp>::value' static constexpr auto value = Tp{}; 

và cũng về việc thiếu initializer:

prog.cc:7:31: error: declaration of 'constexpr const auto wrapper<Tp>::value' has no initializer 

Loại bỏ mâu thuẫn 2. Định nghĩa kết thúc, như mong đợi, với lỗi mối liên kết:

In function `main': prog.cc:(.text+0x8): undefined reference to `wrapper<foo>::value' 

Ví dụ mã online.

Có thể/hợp pháp để sử dụng khởi tạo đồng bộ cho các thành viên lớp constexpr tĩnh không?

+0

này có cái gì để làm với các mẫu tham số: Nó hoạt động như mong đợi nếu loại các thành viên dữ liệu tĩnh không phụ thuộc vào các mẫu tham số, như 'giá trị constexpr auto tĩnh = int {}; ' – dyp

+0

lớp trình bao bọc này thực sự là sự thay thế cho mẫu biến C++ 14 trong gcc <5.0, vì vậy tham số mẫu là phải –

+0

Bạn có cần sử dụng' auto' không? –

Trả lời

0

Đây có thể là sự hiểu lầm của tôi, nhưng tôi sẽ coi

struct wrapper { 
    static constexpr Tp value = Tp{}; 
}; 

là một ví dụ về khởi động thống nhất. Thật vậy, ví dụ mã đầu tiên cũng là khởi tạo đồng nhất. Bản thân tiêu chuẩn chỉ yêu cầu các thành viên constexpr tĩnh được khởi tạo với một biểu thức dấu ngoặc đơn hoặc gán. Điều này, như bạn đã thấy, hoạt động tốt.

Vấn đề có vẻ là với loại khấu trừ từ auto trong ngữ cảnh mẫu và tôi nghi ngờ đó là lỗi triển khai, mặc dù tiêu chuẩn lớn và tôi có thể dễ dàng bỏ sót điều gì đó.

Nếu kích thước bàn tay phải của việc khởi tạo constexpr là biểu thức có loại khó xác định trước, cách giải quyết sẽ là sử dụng decltype, ví dụ:

template <typename Tp> 
struct wrapper { 
    static constexpr decltype(complex-init-expr) value = complex-init-expr; 
}; 

template <typename Tp> 
static constexpr decltype(complex-init-expr) wrapper<Tp>::value; 

hoặc

template <typename Tp> 
struct wrapper { 
    typedef decltype(complex-init-expr) value_type; 
    static constexpr value_type value = complex-init-expr; 
}; 

template <typename Tp> 
static constexpr typename wrapper<Tp>::value_type wrapper<Tp>::value; 
Các vấn đề liên quan