Альтернатива использованию пространства имен в качестве параметра шаблона

#c #templates #c 98

#c #шаблоны #c 98

Вопрос:

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

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

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

Комментарии:

1. Это единственное, что вы хотите сделать? Потому что вы могли бы использовать макрос … 🙂

2. Было бы лучше, если бы вы показали: как вы хотите использовать этот шаблон; вместо этого показывая: как, по вашему мнению, это должно быть написано. Может оказаться, что ответ @StoryTeller не соответствует вашим требованиям, но это правильное исправление для предоставленного вами кода.

3. Верно ли, что большинство пространств имен содержат шаблоны функций и / или функции, которые принимают аргументы из того же и других пространств имен с именем «bar»? У авторов закончились глаголы? Обратите внимание, что сама ситуация сбивает с толку читателя. Это действительно можно сделать однозначным для компилятора C , используя круглые скобки вокруг имени функции для выбора из того же пространства имен или вспомогательных пространств имен для выбора из пространства имен аргументов, но в любом случае это вонючий.

Ответ №1:

За исключением того, что 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.

Вот живой пример того, как все это работает.

Комментарии:

1. Хахаха 🙂 lol, но это не сработает, если в bar foo пространстве имен уже есть пространство имен, поэтому я предполагаю, что OP хотел вызвать его с определителем пространства имен.

2. @Rakete1111 — Есть способы решить и это (я знаю, вы знаете) 🙂 Если у OP есть такой случай, это звучит для меня как основной материал для последующего вопроса.

3. Хм, я знаю обратное (без ADL), но не знаю, как отключить неквалифицированный поиск и получить только ADL.

4. @StoryTeller что делать, если функция bar() не принимает параметр, основанный на типе шаблона? Что, если это просто bar(int) или что-то подобное?

5. @Oracular — Для работы ADL аргумент должен иметь пользовательский тип. Однако в вашем исходном сообщении это не выглядело как возможность. Я полагаю, ваш X псевдоним типа? Насколько мне известно, для этого нет решения, кроме как делать то, что предложил Марек, и использовать a struct вместо пространства имен.

Ответ №2:

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

Поэтому, если вы хотите изменить 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>(amp;a);
foo<Variant2>(amp;b);
  

Комментарии:

1. Я не могу понять, почему, когда кто-то начинает свой первоначальный вопрос с «Я знаю, что не могу использовать пространство имен в качестве параметра шаблона». другой человек начал бы свой ответ с «Пространство имен не может быть параметром шаблона».