如何在C ++中限制函数之外的`using`语句的范围?

时间:2014-06-12 08:35:29

标签: c++ templates c++11 namespaces template-specialization

我想定义一些模板特化的静态成员,如下所示:

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;

...

}

但是为了简化代码(并让它看起来更结构化),我想做这样的事情:

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;
}

...

}

编译器发出错误:expected unqualified-id。有没有办法限制&{34;外部&#34;范围内的using范围?空间?

2 个答案:

答案 0 :(得分:5)

您不能在代码块(即{...})之外嵌套函数。

让我们说我们有这个共同点:

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_;
};
}

您可以import the names into namespace A,通过资格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;
}

但我认为这是不受欢迎的,你认为这是污染。那么你唯一能做的就是use an extra namespace减少::的数量:

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;
}

这可以使您的namespace A清除不需要的类型名称,尽管它引入了一个&#34;实现命名空间&#34; T(这是命名空间的可怕名称!!!)。

第三种选择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;
};
}

请注意,这需要static const个数据成员。您也可以取消struct模板的声明,如下所示:

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

将其使用(在编译时)仅限于您想要的类型。这是我的首选解决方案。

答案 1 :(得分:3)

这是一个难以解决的问题。有几个限制。

  • 模板特化必须在命名空间范围内进行,这会排除您的本地范围大括号{ }
  • 模板专精化与主模板位于同一名称空间中,这排除了namespace detail1 { }内的本地namespace detail2 { }namespace A。虽然g ++错误地接受了这个解决方案,但是Clang正确地拒绝了这个(注意:这是我今天早些时候被卡住的地方并暂时删除了这个答案)。
  • using指令和声明会污染包含此标题的所有客户端的命名空间
  • 生活在inline命名空间中的
  • 模板可以在其所有封闭命名空间内专门化,但声明namespace Ainline仅在A和{B包围时才有效{1}}命名空间序列,这是不可能的。

最干净的方法是将namespace aliases libAlibB用于冗长的A1::A2::...::ANB1::B2::...::BN嵌套命名空间序列,并从中导出这些别名他们的标题。这简化了客户端代码和实际模板特化。

#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

请注意,在重复MyClass1MyClass2时,仍然存在温和的锅炉板块,但代码更加紧凑,并且命名空间别名已经存在。