【问题标题】:Is there a workaround to define a member from inside another namespace?是否有一种解决方法可以从另一个命名空间中定义成员?
【发布时间】:2014-12-18 09:58:32
【问题描述】:

这可能看起来有点深奥,但我有一个这样的类结构,其中一个单例模板类定义在与实际使用它的类不同的命名空间中。

namespace F{
    template<typename>
    struct Foo{
        static Foo instance;
    };
}

namespace B{
    struct Bar{};
    F::Foo<Bar> F::Foo<Bar>::instance; //error C2888
}

产量:

error C2888: 'Foo<void> Foo<void>::instance' : symbol cannot be defined within namespace 'B'

我知道它应该是这样的,但在我的例子中,Foo 是我的库的一部分,Bar 是由客户端定义的,所以它们不一定是同一个命名空间的一部分。定义Foo&lt;void&gt;::instance 的部分是宏的一部分,因此我可以向用户隐藏复杂性。

有什么方法可以让我从另一个命名空间中定义一个类的成员?

【问题讨论】:

  • 在这里查看我的答案:stackoverflow.com/a/2060691/241536
  • 不,这是不可能的。假设两个(!)命名空间有一个 Bar 和一个 F::Foo::instance
  • 反对重复声明。我知道它不起作用,我要求解决方法。该解决方案也不能解决我的问题。我什至不想声明一个类,我只想在里面定义一个符号。
  • @DieterLücking 你能详细说明一下吗?这是解释还是解决方案?
  • @Cheersandhth.-Alf 天哪,是的!非常感谢,这正是我需要的!也许我应该问“如何避免在实现单例时需要定义外部符号。”

标签: c++ templates c++11 namespaces


【解决方案1】:

针对您的特定需求的简单解决方案(假设提供的示例代码是相关的)是使用Meyers' singleton,例如

namespace F{
    template<class>
    struct Foo{
        static auto instance() -> Foo& {
            static Foo the_instance;
            return the_instance;
        }
    };
}

或者,您可以在头文件中提供静态成员的一般定义,由于 ODR 中的模板有特殊豁免,因此可以正常工作:

namespace F{
    template<class>
    struct Foo{
        static Foo instance;
    };

    template<class Type>
    Foo<Type> Foo<Type>::instance;
}

修正

这是最后一种方法的具体示例。它适用于 g++ 4.8.2 和 Visual C++ 12.0 (2013)。我不记得早期编译器版本有什么问题。

main.cpp
auto main() -> int {}
x.h
#pragma once

namespace F{
    template<class>
    struct Foo{
        static Foo instance;
    };

    template<class Type>
    Foo<Type> Foo<Type>::instance;
}
a.cpp
#include "x.h"

#include <iostream>

struct A {};
static bool u = !(std::cout << "A " << &F::Foo<A>::instance << std::endl);

#include "x.h"
a2.cpp
#include "x.h"

#include <iostream>

struct A {};        // Intentionally same as in file "a.cpp"
static bool u = !(std::cout << "A " << &F::Foo<A>::instance << std::endl);
b.cpp
#include "x.h"

#include <iostream>

struct B {};
static bool u = !(std::cout << "B " << &F::Foo<B>::instance << std::endl);

使用 Visual C++ 构建和运行:

H:\dev\test\so\0169>cl main.cpp a.cpp a2.cpp b.cpp /Feb 主文件 a.cpp a2.cpp b.cpp 生成代码... H:\dev\test\so\0169>b 00988A50 00988A50 B 00988A6E H:\dev\test\so\0169>_

【讨论】:

  • 我已经尝试了第二个,但是要么我做错了,要么 MSVC12 不支持它。 Meyers 的单例是解决这个问题的最佳方案。
  • @iFreilicht:我同意,如果您必须提供对公共对象的访问权限,那么 Meyers 的单例可能是我勾勒的两种可能性中最好的。由于您对直接静态成员方法有一些(未指定)问题,因此我添加了一个完整的具体示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多