2013-12-15 17 views
8

C++ có ADL (Truy vấn phụ thuộc đối số), như tên của nó mô tả, ngữ cảnh (không gian tên) của hàm có thể được ngụ ý từ ngữ cảnh (không gian tên) của (bất kỳ) đối số nào.Giải pháp cho sự nghịch đảo của Tra cứu phụ thuộc đối số?

fun(a); // if the type of a is in namespace ns deduce ns::f if available 

Câu hỏi của tôi là liệu kỹ thuật ngược lại có thể thực hiện được không? Ngược lại, ý tôi là nếu ngữ cảnh (không gian tên) có thể được suy ra từ ngữ cảnh của hàm được gọi. Một số loại "Chức năng phụ thuộc tra cứu" (FDL). Mã giả:

ns::fun(a); // deduce ns::a if available 

Tôi không thể tìm ra cách để làm điều đó. Giới hạn này đặc biệt gây phiền toái cho enum s được sử dụng để mã hóa các tùy chọn chức năng. Tôi muốn biết nếu có một kỹ thuật để mô phỏng tính năng này (C++ 11 sẽ là ok quá). Mã giả:

ns::fun(Saturday, Tuesday); // Saturday/Tuesday are enum values in namespace ns; 

Đặc biệt nếu có giải pháp thay thế cho enum s.

Mã này minh họa vấn đề này:

namespace longname{ 
    class A{}; 
    void fun(A const& a){} 
    A global_a; 

    enum Days { Saturday,Sunday,Tuesday,Wednesday,Thursday,Friday}; 
    void gun(Days d1, Days d2){}  
} 

int main(){ 
    longname::A a; 
    fun(a); // cool, longname::fun(a) not necessary, fun is deduced from context 

    longname::fun(global_a); // error, not cool, global_a context not deduced, 
    // must use then longname::fun(longname::global_a) 
    longname::gun(Saturday, Tuesday); // error, particularly not cool, the Saturday is not deduced from context 
    // must use then longname::gun(longname::Saturday, longname::Tuesday) 
    // or at best gun(longname::Saturday, longname::Tuesday) 
} 

EDIT: @jrok gợi ý một cách giải quyết dựa trên định nghĩa namespace lồng nhau. Đối với trường hợp enum, tôi nhận được mã này. Mà vẫn có một số tiếng ồn (có thực sự không có "phụ thuộc" tra cứu ở tất cả) nhưng nó là một sự cải tiến.

namespace longname{ 
    namespace days{ 
     enum _ { Saturday,Sunday,Tuesday,Wednesday,Thursday,Friday}; 
    } 
    void gun(days::_ d1, days::_ d2){} 
} 

int main(){ 
    using namespace longname::days; // some noise still here 
    longname::gun(Saturday, Tuesday); 
} 

Tôi không sử dụng enum class vì sau đó Saturday, Sunday, vv không thể Brough trực tiếp trong phạm vi (trên thực tế using longname::days::_ sẽ cung cấp cho tôi một lỗi biên dịch)

+0

ok, sau khi gửi câu hỏi của tôi: Tôi có một câu hỏi liên quan trên bảng bên phải http://stackoverflow.com/questions/14163667/why-does-c11-not-support-name-lookup-like- này? rq = 1. Có thể cho rằng, sự khác biệt ở đây là tôi không đặt câu hỏi về ngôn ngữ nhưng tôi đang tìm kiếm một kỹ thuật workaround. – alfC

+2

Cách giải quyết: Đặt enum vào một không gian tên lồng nhau và nói 'using namespace longname :: lồng nhau;' trong 'main'. – jrok

+0

@jrok, tuyệt vời, điều đó gần hơn với giải pháp (tôi đã thêm đề xuất của bạn vào câu hỏi). – alfC

Trả lời

2

Có và không. Chủ yếu là không.

Tin xấu là nếu một enum nằm ngoài phạm vi hiện tại, chẳng hạn như Tuesday, v.v ... thì không thể chuyển cho hàm, ngay cả khi hàm đó được khai báo trong không gian tên nơi hiển thị enum. Điều này là do tra cứu đối số xảy ra đầu tiên khi bạn viết một cuộc gọi chức năng và các đối số không thể được chuyển đến gun và sau đó có tra cứu tên xảy ra. Không có gì có thể thay đổi điều này - tuy nhiên cũng có tin tốt.

Trước hết bạn có vẻ cần hành vi có bản đồ ns::foo(arg1, arg2) ->{using namespace ns; ns::foo(arg1, arg2);}. Các cuộc gọi và mẫu chức năng không thể thay đổi điều này nhưng loại macro có thể và tôi đã bao gồm và ví dụ.

Ngoài ra tôi đã đưa ra một ví dụ cơ bản về tra cứu phụ thuộc đối số. Bạn có thể thấy rằng các hàm ngoài phạm vi GetMonday và GetTuesday (trả về enum của bạn ngoài phạm vi) có thể được tìm thấy bằng cách sử dụng cơ chế này đơn giản chỉ vì bạn đã bao gồm một loại từ không gian tên đó. RegisterNamespace::val thêm không gian tên ẩn vào phạm vi khi trình biên dịch đang cố gắng tìm GetMonday và GetMonday trả về một Days cho phép trình biên dịch tìm thấy foo.

Thực sự bạn muốn trình biên dịch thay đổi phạm vi bằng cách thêm các không gian tên bổ sung khi nó gặp một hàm từ một không gian tên khác. Tuy nhiên, trình biên dịch đã xác định các loại đối số vào lúc đó, và thực sự cần chúng để tìm ra các lựa chọn thay thế có thể khác cho hàm.

#include <iostream> 

namespace hidden { 

enum RegisterNamespace { val }; 

enum Days { 
    Monday, 
    Tuesday 
}; 

void foo(Days a , Days b){std::cout << "Called foo\n";} 

Days GetMonday(RegisterNamespace a = val){return Days::Monday;} 
Days GetTuesday(RegisterNamespace b = val){return Days::Tuesday;} 

} 

using namespace std; 

#define UseNamespace(ns, x) do {using namespace ns; x;} while (0) 

int main() 
{ 
    //with a macro 
    UseNamespace(hidden,hidden::foo(Monday, Tuesday)); 

    { 
    //foo is found by argument dependent lookup 
    using hidden::Days; 
    foo(Days::Monday,Days::Tuesday); 
    } 

    { 
    using r = hidden::RegisterNamespace; 
    //foo and GetMonday/GetTuesday are all found by argument dependent lookup 
    foo(GetMonday(r::val),GetTuesday(r::val)); 
    } 

    return 0; 
} 
Các vấn đề liên quan