我知道我不能使用名称空间作为模板参数。但是,我正在尝试实现类似于以下行为:
template <typename T>
void foo(T::X* x)
{
T::bar(x);
}
除了T是名称空间,而不是结构或类。实现与我预期最相似的结果的最佳方法是什么?
答案 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)
命名空间不能是模板参数。 唯一可能的模板参数是:
- std::nullptr_t(自C ++ 11起);
- 一个integral type;
- pointer type(用于对象或功能);
- pointer to member type(用于成员对象或成员函数);
- 一个enumeration type。
因此,如果要根据名称空间更改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);