Альтернатива использованию пространства имен в качестве параметра шаблона - PullRequest
4 голосов
/ 10 апреля 2019

Я знаю, что не могу использовать пространство имен в качестве параметра шаблона.Тем не менее, я пытаюсь добиться поведения, подобного этому:

template <typename T>
void foo(T::X* x)
{
    T::bar(x);
}

За исключением того, что T является пространством имен, а не структурой или классом.Каков наилучший способ достижения результата, наиболее похожего на то, что я ожидаю?

Ответы [ 2 ]

12 голосов
/ 10 апреля 2019

Кроме T это пространство имен, а не структура или класс. Каков наилучший способ достижения результата, наиболее похожего на то, что я ожидаю?

Не упоминайте T.

template <typename X>
void foo(X* x)
{
    bar(x);
}

ADL всегда будет обрабатывать перегрузки из пространства имен, в котором определен X. Пусть механизм сделает свою работу.


Теперь, если вы спрашиваете, как заставить компилятор отдавать предпочтение функциям, найденным 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.

Вот живой пример для всего этого на работе.

5 голосов
/ 10 апреля 2019

Пространство имен не может быть параметром шаблона. Единственные возможные параметры шаблона:

Так что, если вы хотите изменить bar версию в зависимости от пространства имен, это не может быть сделано так, как вы предлагали.
Этого можно достичь, если bar заключен в класс как статическая функция. В таком случае вы можете использовать свой шаблон, тогда этот класс станет параметром шаблона.

Итак, ваш код может выглядеть так:

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);
...