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?
The new entity that is proposed in this paper is called a namespace template. It is a template used to create one or more namespaces. A usage of that template would be a “namespace template instantiation” which is a namespace.
For example, given a specialization Stack<int>, “int” is a template argument. Instantiation: This is when the compiler generates a regular class, method, or function by substituting each of the template's parameters with a concrete type.
A non-type template argument provided within a template argument list is an expression whose value can be determined at compile time. Such arguments must be constant expressions, addresses of functions or objects with external linkage, or addresses of static class members.
In C++ this can be achieved using template parameters. A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.
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.
Namespace can't be a template parameter. The only possible template parameters are:
- 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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With