问题
I know I cannot use a namespace as a template parameter. However, I'm trying to achieve behavior similar to this:
template <typename T>
void foo(T::X* x)
{
T::bar(x);
}
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?
回答1:
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?
Don't mention T
at all.
template <typename X>
void foo(X* x)
{
bar(x);
}
ADL will always pick up on overloads from the namespace where X
is defined. Let the mechanism do its work.
Now, if you are asking how to make the compiler favor functions found by ADL, it's all about manipulating overload resolution. We can do that by limiting what is picked up by regular unqualified name lookup:
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);
}
When the call in foo_detail::foo_impl
is trying to resolve bar
, the first phase in two-phase lookup will pickup the C variable argument function. Now lookup stops, no further enclosing namespaces will be looked in. Which means that only ADL can offer more candidates. And due to how overload resolution works, a C-style variable argument function like we added will be a worse match than anything ADL will find.
Here's a live example for all of this at work.
回答2:
Namespace can't be a template parameter. The only possible template parameters are:
- types
- and values which are: Template parameters and template arguments - cppreference.com
- 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.
So if you want change bar
version depending on namespace it can't be done like you proposed.
It can be achieved if bar
is enclosed in class as a static function. In such case you can use your template, then that class becomes template parameter.
So your code can look lie this:
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);
来源:https://stackoverflow.com/questions/55612759/alternative-to-using-namespace-as-template-parameter