2017-11-04 20 views
6

Tôi gặp vấn đề rất lạ với các mẫu variadic. Có vẻ như gói sai được mở rộng. Dưới đây là một đoạn mã:Gói sai mở rộng trong mẫu variadic

#include <tuple> 

template<typename...> 
struct types {}; 

template<typename = types<>> 
struct Base; 

template<typename... Args1> 
struct Base<types<Args1...>> { 
    template<typename... Args2> 
    static auto construct(Args1... args1, Args2&&... args2) 
     -> decltype(std::make_tuple(args1.forward()..., std::declval<Args2>()...)) 
    { 
     return std::make_tuple(args1.forward()..., std::forward<Args2>(args2)...); 
    } 
}; 

struct Derived : Base<> {}; 

int main() { 
    auto test = &Derived::construct<char const(&)[7]>; 
} 

tôi nhận được lỗi này:

13 : <source>:13:43: error: request for member 'forward' in 'args2#0', which is of non-class type 'const char [7]' 
     -> decltype(std::make_tuple(args1.forward()..., std::declval<Args2>()...)) 
            ~~~~~~^~~~~~~ 
13 : <source>:13:43: error: request for member 'forward' in 'args2#0', which is of non-class type 'const char [7]' 
<source>: In function 'int main()': 
22 : <source>:22:27: error: unable to deduce 'auto' from '& construct<const char (&)[7]>' 
    auto test = &Derived::construct<char const(&)[7]>; 
          ^~~~~~~~~~~~~~~~~~~~~~~~~~~ 
22 : <source>:22:27: note: could not resolve address from overloaded function '& construct<const char (&)[7]>' 
Compiler exited with result code 1 

Tuy nhiên, nó không xảy ra khi các gói có giá trị trong nó:

struct HasForward { int forward() { return 0; } }; 

struct Derived : Base<types<HasForward>> {}; 

Đây là First snippet liveSecond snippet live

Có gì sai với mã này? Đây có phải là lỗi trình biên dịch không? Có cách nào để vượt qua nó và để gói đầu tiên trống không?

+0

kêu vang My ++ biên dịch mà không có vấn đề; Tôi cho rằng đó là lỗi g ++. – max66

Trả lời

3

Is this a compiler bug? Is there any ways to overcome it and leave the first pack empty?

Dường như lỗi trong trình biên dịch của bạn.
Để làm việc xung quanh nó, bạn có thể sử dụng một tuyên bố chức năng (không có định nghĩa bắt buộc) như một trong các ví dụ sau và sử dụng nó để kiểm tra các thông số của bạn:

template<typename... Args1> 
class Base<types<Args1...>> { 
    template<typename... T, typename... U> 
    static auto ret(types<T...>, types<U...>) 
    -> decltype(std::make_tuple(std::declval<T>().forward()..., std::declval<U>()...)); 

public: 
    template<typename... Args2> 
    static auto construct(Args1... args1, Args2&&... args2) 
    -> decltype(ret(types<Args1...>{}, types<Args2...>{})) 
    { 
     return std::make_tuple(args1.forward()..., std::forward<Args2>(args2)...); 
    } 
}; 

Một chút xấu xí, nhưng it works khi gói đầu tiên của bạn là trống (cũng trong C++ 11 theo yêu cầu) và mọi thứ sẽ bị loại bỏ bởi trình liên kết.

--- EDIT

Theo đề nghị của @ W.F. trong các ý kiến ​​(cảm ơn cho đề nghị, tôi đã không nhận thấy nó), nó thậm chí còn dễ dàng hơn để thực hiện điều đó.
Chỉ cần xác định chức năng của bạn vì nó sau:

static auto construct(Args1... args1, Args2&&... args2) 
    -> decltype(std::make_tuple(std::declval<Args1>().forward()..., std::declval<Args2>()...)) 
{ 
    return std::make_tuple(args1.forward()..., std::forward<Args2>(args2)...); 
} 
+0

cũng có thể đơn giản hơn: 'std :: declval () .forward() ...' dường như hoạt động. Đã cố gắng thực hiện thử nghiệm tâm trí để làm cho mã OPs không đúng định dạng nhưng cũng không thành công :) –

+0

@ W.F. Điểm tốt. Tôi không để ý. Tôi có thể sử dụng đề xuất của bạn để tích hợp câu trả lời không? – skypjack

+1

Chắc chắn hãy tiếp tục! ... –

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