#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
псевдоним типа? Насколько мне известно, для этого нет решения, кроме как делать то, что предложил Марек, и использовать astruct
вместо пространства имен.
Ответ №2:
Пространство имен не может быть параметром шаблона. Единственными возможными параметрами шаблона являются:
- типы
- и значения, которые являются: Параметры шаблона и аргументы шаблона — cppreference.com
- std::nullptr_t (начиная с C 11);
- интегральный тип;
- тип указателя (на объект или на функцию);
- указатель на тип члена (на объект-член или на функцию-член);
- тип перечисления.
Поэтому, если вы хотите изменить 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. Я не могу понять, почему, когда кто-то начинает свой первоначальный вопрос с «Я знаю, что не могу использовать пространство имен в качестве параметра шаблона». другой человек начал бы свой ответ с «Пространство имен не может быть параметром шаблона».