Alternative to using namespace as template parameter

假如想象 提交于 2021-01-27 06:30:46

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!