2011-10-25 23 views
8

Tóm tắt: Tôi muốn kết thúc với một hàm suy ra các loại chính xác nó được gọi và lấy (ví dụ) một bộ chuyển tiếp chúng (các loại sẽ được khác với các loại chính xác mà hàm được gọi với).Hiểu biết về các loại gốc, trong khi đồng thời chuyển tiếp

Tôi đang cố gắng cố gắng "biết" qua việc khấu trừ các loại đối số cho một hàm nhất định, trong khi đồng thời chuyển tiếp chúng. Tôi nghĩ rằng tôi có thể thiếu một cái gì đó rất quan trọng về cách thức hoạt động của nó.

#include <tuple> 
#include <string> 
#include <functional> 

template <typename ...Args> 
struct unresolved_linker_to_print_the_type { 
    unresolved_linker_to_print_the_type(); 
}; 

void f(int,double,void*,std::string&,const char*) { 
} 

template <typename F, typename ...Args> 
void g1(F func, Args&&... args) { 
    unresolved_linker_to_print_the_type<Args...>(); 
    auto tuple = std::forward_as_tuple(args...); 
    unresolved_linker_to_print_the_type<decltype(tuple)>(); 
} 

template <typename F, typename T, typename ...Args> 
void g2(F func, const T& tuple, Args... args) { 
    unresolved_linker_to_print_the_type<Args...>(); 
    unresolved_linker_to_print_the_type<decltype(tuple)>(); 
} 

int main() { 
    int i; 
    double d; 
    void *ptr; 
    std::string str; 
    std::string& sref = str; 
    const char *cstr = "HI"; 

    g1(f, i,d,ptr,sref,cstr); 
    g2(f, std::forward_as_tuple(i,d,ptr,sref,cstr), i,d,ptr,sref,cstr); 
} 

Những gì tôi muốn thấy là một kịch bản mà khi chức năng của tôi (ví dụ g1 hoặc g2) được gọi nó biết và có thể sử dụng cả hai loại gốc - int,double,void*,std::string&,const char* các arugments chuyển quá.

Trong trường hợp này, tôi dường như không thể tìm thấy thông tin này từ bên trong g1 hoặc g2. Các (cố ý, để in ra các loại) mối liên kết lỗi cho tôi trong g1 đó là:

int&, double&, void*&, std::string&, char const*& 
int&, double&, void*&, std::string&, char const*& 

và trong g2:

int, double, void*, std::string, char const* 
int&, double&, void*&, std::string&, char const*& 

Có hai điều tôi không nhận được ở đây:

  1. Tại sao không có loại in nào (thông qua lỗi trình liên kết) khớp với những gì tôi thực sự chuyển vào? (int,double,void*,std::string&,const char). Tôi có thể suy ra những gì tôi thực sự đã được thông qua? Tốt hơn là với cú pháp "tự nhiên", tức là mọi thứ chỉ một lần và không có gì được viết rõ ràng. Tôi rõ ràng có thể viết:

    g2<decltype(&f),decltype(std::forward_as_tuple(i,d,ptr,sref,cstr)),int,double,void*,std::string&,const char*>(f,std::forward_as_tuple(i,d,ptr,sref,cstr),i,d,ptr,sref,cstr); 
    

    nhưng đó là "khó sử dụng" để nói rằng ít nhất!

  2. Trong g1 sự hiện diện của && trong khai báo chữ ký hàm dường như thay đổi các loại trong thông số mẫu Args. Hãy so sánh điều đó với:

    template <typename T> 
    void test(T t); 
    

    Hoặc:

    template <typename T> 
    void test(T& t); 
    

    sử dụng một trong những người có:

    int i; 
    test(i); 
    

    không làm thay đổi loại T. Tại sao số && thay đổi loại T khi & không?

+0

Re: "tl; dr" - 2p2er? –

+0

Trình biên dịch nào bạn đang sử dụng có hỗ trợ các tham số mẫu của vectơ? –

+0

@JohnDibling g ++ 4.7.0, 20111010 sửa đổi thân cây 179769 biên dịch nhưng không liên kết (tức là những gì tôi mong đợi để tôi có thể thấy các loại lỗi liên kết) – Flexo

Trả lời

2

trả lời cho câu hỏi đầu tiên:

luận cứ chức năng là biểu, không loại. Sự khác biệt giữa hai điều này được thể hiện trong chương 5 [expr], p5:

Nếu một biểu thức ban đầu có loại “tham chiếu đến T” (8.3.2, 8.5.3), loại được điều chỉnh thành T trước khi phân tích thêm.

Do đó, không có sự khác biệt nào giữa chừng g(str)g(sref). g() luôn thấy std::string và không bao giờ là tham chiếu.

Biểu thức bổ sung có thể là lvalue hoặc rvalue (thực sự đó là đơn giản hóa các quy tắc C++ 11, nhưng nó đủ gần cho cuộc thảo luận này - nếu bạn muốn chi tiết trong 3.10 [basic.lval]).

trả lời cho câu hỏi thứ hai:

thông số mẫu có dạng:

template <class T> 
void g(T&&); 

là đặc biệt. Họ không giống T, T&, hoặc thậm chí const T&& theo cách sau:

Khi T&& liên kết với một giá trị trái, T là suy luận như một loại tài liệu tham khảo giá trị trái, nếu không T deduces chính xác theo các quy tắc khấu trừ bình thường.

Ví dụ:

int i = 0; 
g(i); // calls g<int&>(i) 
g(0); // calls g<int>(0) 

Hành vi này là để hỗ trợ cái gọi là hoàn hảo chuyển tiếp mà thường trông giống như:

struct A{}; 

void bar(const A&); 
void bar(A&&); 

template <class T> 
void foo(T&& t) 
{ 
    bar(static_cast<T&&>(t)); // real code would use std::forward<T> here 
} 

Nếu ai gọi foo(A()) (một rvalue A), T deduces mỗi bình thường quy tắc là A. Bên trong của foo, chúng tôi truyền t đến một số A&& (giá trị) và gọi bar. Tình trạng quá tải của bar mất một rvalue A sau đó được chọn. I E. nếu chúng tôi gọi số foo với giá trị bằng, thì foo gọi số bar với giá trị bằng rvalue.

Nhưng nếu chúng tôi gọi foo(a) (giá trị A), thì T khấu trừ là A&. Bây giờ các diễn viên trông giống như:

static_cast<A& &&>(t); 

mà theo các tài liệu tham khảo sụp đổ quy tắc đơn giản để:

static_cast<A&>(t); 

Tức là các lvalue t được đúc thành một lvalue (một diễn viên không có op), và do đó quá tải bar tham gia một lvalue được gọi là. I E. nếu chúng tôi gọi tới số foo với một số tiền, sau đó gọi sốgọi bar với một số tiền. Và đó là cụm từ chuyển tiếp hoàn hảo xuất phát từ đó.

+1

Vì vậy, tóm lại không có cách nào để suy ra thực tế rằng 'sref' là một tham chiếu và' ref' không và '&&' rõ ràng là một trường hợp đặc biệt của loại khấu trừ. – Flexo

+0

Cảm ơn bạn đã có câu trả lời thực sự sâu sắc - Tôi e rằng đây có thể là trường hợp nên có vẻ như tôi sẽ đi với kế hoạch B! – Flexo

+0

Cảm ơn bạn awoodland. Đó là sự hào phóng của bạn. –

0

loại (ngay cả trong C++) chủ yếu là khái niệm kiểu biên dịch (ngoại trừ khóa học RTTI trong vtables).

Nếu bạn cần các loại động hoàn toàn, thì C++ có thể không phải là ngôn ngữ tốt nhất cho điều đó.

Bạn có thể mở rộng GCC (thực tế là g++, giả sử ít nhất là 4.6) với một plugin hoặc một mở rộng GCC MELT (MELT là ngôn ngữ cấp cao nhất để mở rộng GCC) mà bạn muốn (ví dụ như cung cấp thêm nội dung mã hóa kiểu đối số của nó trong một số chuỗi không đổi, v.v. ...), nhưng điều đó đòi hỏi một số công việc (và cụ thể cho GCC).

Nhưng tôi không hiểu tại sao bạn muốn làm những điều baroque như vậy trong C. Nếu gõ động là rất quan trọng với bạn, tại sao bạn không sử dụng một ngôn ngữ động gõ?

+0

Tôi không muốn gõ động trong C++, tôi muốn thực hiện gõ tĩnh, nhưng tìm hiểu thêm thông tin về các loại đó thời gian hơn tôi biết làm thế nào. – Flexo

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