使用命名空间作为模板参数的替代方法
Alternative to using namespace as template parameter
我知道我不能将命名空间用作模板参数。但是,我正在尝试实现与此类似的行为:
template <typename T>
void foo(T::X* x)
{
T::bar(x);
}
除了 T 是命名空间而不是结构或 class。实现与我期望的结果最相似的最佳方法是什么?
Except T is a namespace rather than a struct or a class. What is the best way to achieve the most similar result to what I am expecting?
根本不提T
。
template <typename X>
void foo(X* x)
{
bar(x);
}
ADL 将始终从定义 X
的命名空间中获取重载。让机制发挥作用。
现在,如果您要问如何让编译器 favor 函数被 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。
命名空间不能是模板参数。
唯一可能的模板参数是:
- std::nullptr_t (since C++11);
- an integral type;
- a pointer type (to object or to function);
- a pointer to member type (to member object or to member function);
- an enumeration type.
因此,如果您想根据命名空间更改 bar
版本,则无法像您建议的那样完成。
如果把bar
作为静态函数括在class里面就可以实现。在这种情况下,您可以使用您的模板,然后 class 成为模板参数。
所以你的代码看起来像这样:
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);
我知道我不能将命名空间用作模板参数。但是,我正在尝试实现与此类似的行为:
template <typename T>
void foo(T::X* x)
{
T::bar(x);
}
除了 T 是命名空间而不是结构或 class。实现与我期望的结果最相似的最佳方法是什么?
Except T is a namespace rather than a struct or a class. What is the best way to achieve the most similar result to what I am expecting?
根本不提T
。
template <typename X>
void foo(X* x)
{
bar(x);
}
ADL 将始终从定义 X
的命名空间中获取重载。让机制发挥作用。
现在,如果您要问如何让编译器 favor 函数被 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。
命名空间不能是模板参数。 唯一可能的模板参数是:
- std::nullptr_t (since C++11);
- an integral type;
- a pointer type (to object or to function);
- a pointer to member type (to member object or to member function);
- an enumeration type.
因此,如果您想根据命名空间更改 bar
版本,则无法像您建议的那样完成。
如果把bar
作为静态函数括在class里面就可以实现。在这种情况下,您可以使用您的模板,然后 class 成为模板参数。
所以你的代码看起来像这样:
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);