проблема разрешения перегрузки шаблона
Учитывая этот код:
#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
1 ответ:
Прежде всего, избегайте специализированных шаблонов функций, предпочитайте перегрузку. См. Статья Херб Саттер на потенциальные подводные камни.
Во-вторых, проблема, с которой вы столкнулись, связана с тем, как поиск имен работает для зависимых имен в шаблонах функций. Внутри
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.