【问题标题】:How to limit scope of `using` statement outside of function in C++?如何限制 C++ 函数之外的“使用”语句的范围?
【发布时间】:2014-06-12 08:35:29
【问题描述】:

我想定义一些模板特化的静态成员,像这样:

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。有没有办法将using 范围限制在“外部”空间中?

【问题讨论】:

  • 你是用C++11模式编译的吗?
  • @TemplateRex 是的,我愿意。
  • 我使用命名空间别名的新方法取消了我今天早些时候的答案。

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


【解决方案1】:

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

假设我们有这个共同点:

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

尽管它引入了“实现命名空间”T(这对于命名空间来说是一个糟糕的名称!!!),但它可以让您的 namespace A 清除不需要的类型名。

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

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

【讨论】:

    【解决方案2】:

    这是一个很难解决的问题。有几个限制条件。

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

    最简洁的方法是使用 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 的重复中仍然有轻微的样板症状,但代码更紧凑,命名空间别名就位。

    【讨论】:

      猜你喜欢
      • 2015-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-03
      • 1970-01-01
      • 2022-01-23
      • 1970-01-01
      相关资源
      最近更新 更多