2014-06-12 16 views
6

Tôi muốn xác định một số thành viên tĩnh của mẫu chuyên môn, như thế này:Làm thế nào để giới hạn phạm vi của `sử dụng` tuyên bố bên ngoài của chức năng trong C + +?

namespace A { 

template <> int C<A1::A2::...::MyClass1>::member1_ = 5; 
template <> int C<A1::A2::...::MyClass1>::member2_ = 5; 
template <> int C<A1::A2::...::MyClass1>::member3_ = 5; 

template <> int C<B1::B2::...::MyClass2>::member1_ = 6; 
template <> int C<B1::B2::...::MyClass2>::member2_ = 6; 
template <> int C<B1::B2::...::MyClass2>::member3_ = 6; 

... 

} 

Nhưng để đơn giản hóa mã (và làm cho nó trông có cấu trúc hơn), tôi muốn làm một cái gì đó như thế này:

namespace A { 

{ 
    using T = A1::A2::...::MyClass1; 
    template <> int C<T>::member1_ = 5; 
    template <> int C<T>::member2_ = 5; 
    template <> int C<T>::member3_ = 5; 
} 

{ 
    using T = B1::B2::...::MyClass2; 
    template <> int C<T>::member1_ = 6; 
    template <> int C<T>::member2_ = 6; 
    template <> int C<T>::member3_ = 6; 
} 

... 

} 

Trình biên dịch cho một lỗi: expected unqualified-id. Có cách nào để giới hạn phạm vi using trong một không gian "bên ngoài"?

+1

bạn đã biên dịch ở chế độ C++ 11 chưa? – TemplateRex

+0

@TemplateRex Có, tôi có. –

+0

Tôi đã hủy xóa câu trả lời trước đó của mình hôm nay với một cách tiếp cận mới bằng cách sử dụng bí danh không gian tên. – TemplateRex

Trả lời

5

Bạn không thể khối mã tổ (ví dụ: {...}) chức năng bên ngoài.

Hãy nói rằng chúng tôi có phần này điểm chung:

namespace A1 { namespace A2 { 
    class MyClass1; 
}} 

namespace B1 { namespace B2 { 
    class MyClass2; 
}} 

namespace A { 
template<typename T> 
struct C 
{ 
    static int member1_; 
    static int member2_; 
    static int member3_; 
}; 
} 

Bạn có thể import the names into namespace A, làm cho chúng có sẵn thông qua trình độ A:::

namespace A { 
using A1::A2::MyClass1; 
template <> int C<MyClass1>::member1_ = 5; 
template <> int C<MyClass1>::member2_ = 5; 
template <> int C<MyClass1>::member3_ = 5; 

using B1::B2::MyClass2; 
template <> int C<MyClass2>::member1_ = 6; 
template <> int C<MyClass2>::member2_ = 6; 
template <> int C<MyClass2>::member3_ = 6; 
} 

nhưng tôi cho rằng là không mong muốn và bạn thấy điều này là ô nhiễm. Vì vậy, sau đó điều duy nhất bạn có thể làm là use an extra namespace để giảm số lượng :::

namespace A { 
namespace T { 
using T1 = A1::A2::MyClass1; 
using T2 = B1::B2::MyClass2; 
} 

template <> int C<T::T1>::member1_ = 5; 
template <> int C<T::T1>::member2_ = 5; 
template <> int C<T::T1>::member3_ = 5; 


template <> int C<T::T2>::member1_ = 6; 
template <> int C<T::T2>::member2_ = 6; 
template <> int C<T::T2>::member3_ = 6; 
} 

Điều này sẽ giúp bạn namespace A rõ ràng về typenames không mong muốn, mặc dù nó giới thiệu một "không gian tên thực hiện" T (mà là một tên khủng khiếp cho một không gian tên !!!).

Một lựa chọn thứ ba specializes struct template C for the types you want:

namespace A{ 
template<> 
struct C<A1::A2::MyClass1> 
{ 
    static const int member1_ = 5; 
    static const int member2_ = 5; 
    static const int member3_ = 5; 
}; 

template<> 
struct C<B1::B2::MyClass2> 
{ 
    static const int member1_ = 5; 
    static const int member2_ = 5; 
    static const int member3_ = 5; 
}; 
} 

Lưu ý rằng điều này đòi hỏi static const thành viên dữ liệu. Bạn cũng có thể làm được ngay với một tuyên bố của struct mẫu như vậy:

namespace A { 
template<typename T> 
struct C; 
} 

để hạn chế việc sử dụng nó (tại thời gian biên dịch) để chỉ các loại mà bạn muốn. Điều này sẽ cho tôi giải pháp ưa thích của tôi.

3

Đây là vấn đề khó giải quyết. Có một số ràng buộc.

  • chuyên môn về khuôn mẫu phải xảy ra ở phạm vi không gian tên, quy tắc này ra ngoài phạm vi địa phương của bạn { }.
  • chuyên môn mẫu sống trong cùng một không gian tên làm mẫu chính, quy tắc này ra địa phương namespace detail1 { }namespace detail2 { } bên trong namespace A. Mặc dù g ++ chấp nhận không chính xác giải pháp này, nhưng Clang đã từ chối chính xác điều này (Lưu ý: đây là nơi tôi đã bị mắc kẹt trước đó ngày hôm nay và tạm thời xóa câu trả lời này).
  • using chỉ thị và khai báo ô nhiễm không gian tên của tất cả khách hàng bao gồm tiêu đề này
  • mẫu sống trong inline namespace có thể được chuyên trong tất cả các không gian tên kèm theo họ, nhưng tuyên bố namespace Ainline chỉ hoạt động nếu nó được bao bọc bởi cả AB chuỗi không gian tên, điều này là không thể.

Phương pháp sạch nhất là sử dụng namespace aliaseslibAlibB cho dài A1::A2::...::ANB1::B2::...::BN chuỗi namespace lồng nhau, và có thể export các bí danh từ tiêu đề của họ. Điều này đơn giản hóa cả mã máy khách và các chuyên môn mẫu thực tế.

#include <iostream> 

// file C.h 

namespace A { 

template<class T> 
struct C 
{ 
    static int member1_, member2_, member3_; 
}; 

} // namespace A 

// file A.h 

namespace A1 { namespace A2 { 

struct MyClass1 {}; 

}} // namespace A1, A2 

// export namespace alias to hide implementation details 
namespace libA = A1::A2;  

namespace A { 

template <> int C<libA::MyClass1>::member1_ = 5; 
template <> int C<libA::MyClass1>::member2_ = 5; 
template <> int C<libA::MyClass1>::member3_ = 5; 

} // namespace A 

// file B.h 

namespace B1 { namespace B2 { 

struct MyClass2 {}; 

}} // namespace B1, B2 

// export namespace alias to hide implementation details 
namespace libB = B1::B2;  

namespace A { 

template <> int C<libB::MyClass2>::member1_ = 6; 
template <> int C<libB::MyClass2>::member2_ = 6; 
template <> int C<libB::MyClass2>::member3_ = 6; 

} // namespace A 

// file main.cpp 

int main() 
{ 
    std::cout << A::C<libA::MyClass1>::member1_ << "\n"; 
    std::cout << A::C<libA::MyClass1>::member2_ << "\n"; 
    std::cout << A::C<libA::MyClass1>::member3_ << "\n"; 
    std::cout << A::C<libB::MyClass2>::member1_ << "\n"; 
    std::cout << A::C<libB::MyClass2>::member2_ << "\n"; 
    std::cout << A::C<libB::MyClass2>::member3_ << "\n";  
} 

Live Example.

Lưu ý rằng vẫn còn một biểu tượng hơi ấm của nồi hơi trong sự lặp lại của MyClass1MyClass2, nhưng mã nhỏ gọn hơn nhiều với các bí danh không gian tên tại chỗ.

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