2016-04-29 3 views
2

Учитывая этот код:шаблон разрешения перегрузки Проблема

#include <string> 
#include <vector> 
#include <iostream> 

template <typename T> 
std::string stringify(const T&) { 
    return "{?}"; 
} 

template <typename T> 
std::string proxy(const T& in) { 
    return stringify(in); 
} 

// trying to specialize "stringify()" 

template <typename T> 
std::string stringify(const std::vector<T>& in) { 
    return "vector specialization!"; 
} 

template <> 
std::string stringify(const std::vector<int>& in) { 
    return "INT vector specialization!"; 
} 

int main() { 
    std::cout << proxy(1); // calls the 1st 

    std::vector<int> intVec; 
    std::cout << proxy(intVec); // calls the 1st 

    std::vector<double> dblVec; 
    std::cout << proxy(dblVec); // calls the 1st 

    return 0; 
} 

Как я могу специализироваться stringify() для vector<> после proxy<>?

В настоящее время я получаю {?}{?}{?}

Если удалить этот один - stringify(const std::vector<T>& in) то vector<int> начинает получать называется потому, что это будет специализация первого.

Тогда я бы {?}INT vector specialization!{?}

Есть ли способ, чтобы вызвать любого из 2 вектора специализации stringification функций из proxy() - если они определены в прошлом - после того, как функции proxy()?

Есть ли способ частично специализироваться на vector<> и до сих пор получить звонок от proxy<>?

Я не хочу, чтобы специализироваться на vector<int>, vector<double>, vector<UserType> ...

EDIT: забыл упомянуть мне это нужно для C++98

ответ

3

Прежде всего, избегать, специализирующихся шаблонов функций, предпочитает перегрузка. См. Herb Sutter's article о потенциальных ловушках.

Во-вторых, проблема, с которой вы сталкиваетесь, связана с тем, как поиск имен работает для зависимых имен в шаблонах функций. Внутри proxy<T>, stringify - зависимое имя - это зависит от T. Это имя будет рассмотрено в точке определения шаблона (который найдет stringify<T>(const T&), а не другую перегрузку) и снова в точке инстанцирования в ассоциированном пространстве имен аргументов (который будет std). Ни один из этих поисков не найдет ваши другие функции.

Это вторая часть поиска - зависимый от аргументов поиск - что мы можем использовать. Давайте просто придерживаться все в одном пространстве имен (которое я именования N произвольно, не стесняйтесь переименовать в зависимости от обстоятельств):

namespace N { 
    struct helper { }; 

    template <typename T> 
    std::string stringify(helper, const T&) { 
     return "{?}"; 
    } 
} 

template <typename T> 
std::string proxy(const T& in) { 
    return stringify(N::helper(), in); 
} 

Хорошо, до сих пор мы не изменили абсолютно ничего. Мы все равно получаем {?} во всех случаях. Но теперь мы можем придерживаться дальнейших перегрузок (не специализации) из stringify еще в этом пространстве имен, но после определения proxy:

namespace N {  
    template <typename T> 
    std::string stringify(helper, const std::vector<T>&) { 
     return "vector overload!"; 
    } 

    std::string stringify(helper, const std::vector<int>&) { 
     return "INT vector overload!"; 
    } 
} 

этих двух перегрузок будет найден во второй фазе имени поиска, поскольку N является ассоциированным пространством имен helper. Теперь proxy(intVFec) найдет все три перегрузки stringify вместо одного. И теперь ваш код печатает:

{?}INT vector overload!vector overload! 

по вашему желанию. Ни одно из указанных выше не требует C++ 11.

+0

спасибо большое! ты спас мою задницу!Мне нравится, когда работает C++ magic, и я этого не понимаю - все еще пытаюсь НЕ узнать о ADL :) жизнь коротка. – onqtam

+0

@onqtam ADL очень важен - ведь это как 'std :: cout <<« Hello, World! »' Работает! – Barry

+0

только что выяснил, что это не скомпилировано под VC++ 6 ... возможно, ADL сломан (только при использовании шаблонов для перегрузок! Бесполезные перегрузки функций в порядке) - он говорит в '' 'proxy()' '', что вызов является неоднозначным, если существует более 1 специализации. Может быть, его время отказаться от поддержки для него – onqtam

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