【问题标题】:Alternative to using namespace as template parameter替代使用命名空间作为模板参数
【发布时间】:2026-02-01 22:15:01
【问题描述】:

我知道我不能将命名空间用作模板参数。但是,我正在尝试实现与此类似的行为:

template <typename T>
void foo(T::X* x)
{
    T::bar(x);
}

除了 T 是命名空间而不是结构或类。获得与我的预期最相似的结果的最佳方法是什么?

【问题讨论】:

  • 这是你唯一想做的事吗?因为您可以使用宏... :)
  • 最好显示:你想如何使用这个模板;而是显示:您认为应该如何编写。事实证明,@StoryTeller 的回答不符合您的要求,但它是您提供的代码的有效修复。
  • 大多数命名空间是否包含函数模板和/或函数,这些函数模板和/或函数接受来自相同命名空间和其他名为“bar”的命名空间的参数?作者用完了动词吗?请注意,这种情况对人类读者来说是令人困惑的。通过在函数名称周围使用括号从相同的命名空间或辅助命名空间从参数命名空间中选择,这确实可以使 C++ 编译器明确,但无论如何它都很臭。

标签: c++ templates c++98


【解决方案1】:

除了 T 是命名空间而不是结构或类。获得与我的预期最相似的结果的最佳方法是什么?

别提T

template <typename X>
void foo(X* x)
{
    bar(x);
}

ADL 将始终从定义 X 的命名空间中获取重载。让机制发挥作用。


现在,如果您要问如何使编译器支持 ADL 找到的函数,那就是处理重载决议。我们可以通过限制常规非限定名称查找获取的内容来做到这一点:

namespace foo_detail {
    void bar(...);
    template<typename X>
    void foo_impl(X* x) {
        bar(x);
    }
}

template <typename X>
void foo(X* x)
{
    foo_detail::foo_impl(x);
}

foo_detail::foo_impl 中的调用试图解析bar 时,两阶段查找的第一阶段将获取C 变量参数函数。现在查找停止,将不再查找封闭的命名空间。这意味着只有 ADL 可以提供更多候选。而且由于重载解析的工作原理,像我们添加的 C 风格的变量参数函数将比 ADL 找到的任何东西都更差。

这里有一个live example 用于所有这些工作。

【讨论】:

  • 哈哈哈 :) 大声笑,但是如果bar 已经在foo 的命名空间中,这将不起作用,这就是为什么我假设OP 想用命名空间限定符来调用它。
  • @Rakete1111 - 也有办法解决这个问题(我知道你知道):) 如果 OP 手上有这样的案例,在我看来,这听起来像是后续问题的主要材料。
  • 嗯,我知道反过来(没有 ADL),但不知道如何禁用不等式查找,只获取 ADL。
  • @StoryTeller 如果函数 bar() 不采用基于模板类型的参数怎么办?如果它只是 bar(int) 或类似的东西怎么办?
  • @Oracular - 要使 ADL 工作,参数必须是用户定义的类型。但是,在您的原始帖子中,这看起来不太可能。我想您的 X 是类型别名?据我所知,没有解决方案,除了按照 Marek 的建议做,并使用 struct 代替命名空间。
【解决方案2】:

命名空间不能是模板参数。 唯一可能的模板参数是:

因此,如果您想根据命名空间更改 bar 版本,则无法像您建议的那样完成。
如果bar作为静态函数包含在类中就可以实现。在这种情况下,您可以使用您的模板,然后该类成为模板参数。

所以你的代码看起来是这样的:

class Variant1 {
public:
    typedef int* argType;

    static void bar(argType i) {
        std::cout << (*i + 1);
    }
};
class Variant2 {
public:
    typedef size_t* argType;

    static void bar(argType i) {
        std::cout << (*i - 1);
    }
};

template <typename T>
void foo(typename T::argType x)
{
    T::bar(x);
}

//usage
size_t a = 1;
int x = 1;

foo<Variant1>(&a);
foo<Variant2>(&b);

【讨论】:

  • 我不明白为什么有人以“我知道我不能将命名空间用作模板参数”开始他们的原始问题。另一个人会以“命名空间不能是模板参数”开始他们的响应。