Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alternative to using namespace as template parameter

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?

like image 246
Oracular Avatar asked Apr 10 '19 12:04

Oracular


People also ask

Can you template a namespace?

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.

Which is a correct example of template parameters?

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.

Can we use non-type parameters as argument templates?

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.

How do you pass a parameter to a template in C++?

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.


2 Answers

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.

like image 95
StoryTeller - Unslander Monica Avatar answered Nov 09 '22 15:11

StoryTeller - Unslander Monica


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);
like image 31
Marek R Avatar answered Nov 09 '22 16:11

Marek R