2011-04-18 2 views
8

Почему это не удается скомпилировать с помощью GCC 4.4?Шаблоны функций перегрузки в пространствах имен

template<typename T> 
class A { 
public: 
    void foo() { 

    } 

private: 
    T x; 
}; 

namespace Ns { 
template<typename T> 
void do_it (A<T> a) { 
    a.foo(); 
} 
}; 

template<typename T> 
void myfun (T x) { 
    Ns::do_it (x); 
} 

template<typename T> 
class B { 
public: 
    void bar() { 

    } 

private: 
    T x; 
}; 

namespace Ns { 
template<typename T> 
void do_it (B<T> b) { 
    b.bar(); 
} 
}; 

int main() { 
    A<int> a; 
    B<int> b; 

    myfun (a); 
    myfun (b); // error: no matching function call to do_it(B<int>&) 

    return 0; 
} 

Он должен иметь что-то делать с пространством имен do_it. Когда я удаляю пространство имен вокруг него, оно компилируется.

Фон: Я создаю набор функций, которые могут использоваться со многими различными классами контейнеров. Для равномерного управления различными интерфейсами я использую автономные функции, которые перегружены для каждого из классов контейнеров. Эти функции должны быть помещены в пространство имен, чтобы избежать загромождения им глобального пространства имен.

Определения для B считаются поступающими из другого заголовочного файла, чем определения для A, поэтому переупорядочение не является вариантом.

+0

Опечатка! был проглочен HTML. –

+0

VS 2010 компилирует приведенный выше код, и я считаю, что это правильно, но это сложный пример. Хороший вопрос! –

+0

То же самое с VS2008, я только что проверил. Может ли это быть ошибкой в ​​GCC или их интерпретация просто отличается от Microsoft? Тот факт, что он работает без пространства имен, указывает на то, что он является ошибкой, не так ли? –

ответ

6

Причина в том, что только ADL выполняется в точке вызова. Другие функции поиска выполняются только в определении шаблона функции myfun.

И в этом контексте определения объявляется только перегрузка do_it, принимающая A<int>.

Редактирование: Если вы хотите иметь стандартную ссылку для этого, обратитесь к [temp.dep.candidate] и [temp.res] p1.

+0

Есть ли стандартный способ решения этой проблемы с помощью пространств имен? –

+2

@Mark, если вы хотите иметь функции в пространстве имен 'Ns', вы можете получить' B 'из фиктивного класса, определенного в этом пространстве имен, чтобы ADL рассмотрел пространство имен Ns. Или вы можете передать аргументы шаблона в 'B ', которые связывают сгенерированную специализацию с 'Ns'. Например, 'B >' (ADLAssociator может быть просто шаблоном небольшого класса, хранящим только 'T t;'). Или вы передаете эти классы ассоциаторов в качестве дополнительных фиктивных аргументов: 'B '. Есть много вариантов для этого. Кажется, что самое чистое - просто вывести 'B' из класса или определить его в' NS'. –

+5

Что касается изменения свободной функции в статическом члене класса: 'namespace Ns {template struct dispatch; } '(объявить его перед собой), затем для каждого нового типа добавьте специализацию:' namespace Ns {template struct dispatch < B> {static void do_it (B x) {x.bar()}}; } ', и имеют' template void myfunc (T t) {Ns :: dispatch :: do_it (t); } ' –

Смежные вопросы