使用命名空间作为模板参数的替代方法

时间:2019-04-10 12:37:43

标签: c++ templates c++98

我知道我不能使用名称空间作为模板参数。但是,我正在尝试实现类似于以下行为:

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

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

2 个答案:

答案 0 :(得分:12)

  

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

完全不提T

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

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


现在,如果您要问如何使ADL找到的编译器 favor 函数,那么所有操作都是关于重载解析的。我们可以通过限制常规不合格名称查找所提取的内容来做到这一点:

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

答案 1 :(得分:5)

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

  

因此,如果要根据名称空间更改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);