I want to define some static members of template specialization, like this:
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;
...
}
But to simplify the code (and make it look more structured), I want to do something like this:
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;
}
...
}
The compiler gives an error: expected unqualified-id
. Are there ways to limit the using
scope in an "outer" space?
You cannot nest code blocks (i.e. {...}
) outside functions.
Let's say we have this part in common:
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_;
};
}
You can either import the names into namespace A
, making them available through the qualification 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;
}
but I assume that is unwanted and you see this as pollution. So then the only thing you can do is use an extra namespace to decrease the number of ::
:
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;
}
This keeps your namespace A
clear of unwanted typenames, although it introduces an "implementation namespace" T
(which is a terrible name for a namespace!!!).
A third alternative 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;
};
}
Note that this requires static const
data members. You can also do away with a declaration of the struct
template like so:
namespace A {
template<typename T>
struct C;
}
to limit its use (at compile time) to only the types you want. This would me my preferred solution.
This is a difficult problem to solve. There are several constraints.
{ }
. namespace detail1 { }
and namespace detail2 { }
inside namespace A
. Although g++ incorrectly accepts this solution, but Clang correctly rejects this (Note: this was where I was stuck earlier today and temporarily deleted this answer).using
directives and declarations pollute the namespace of all clients who include this headerinline
namespaces can be specialized inside all their enclosing namespace but declaring namespace A
to be inline
only works if it is enclosed by both the A
and B
namespace sequences, which is impossible.The cleanest approach is to use namespace aliases libA
and libB
for the lengthy A1::A2::...::AN
and B1::B2::...::BN
sequences of nested namespaces, and to export those aliases from their headers. This simplifies both client code and the actual template specializations.
#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.
Note that there is still a mild sympton of boiler plate in the repetition of the MyClass1
and MyClass2
, but the code is much more compact with the namespace aliases in place.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With