2

Given this code:

#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;
}

How can I specialize stringify() for vector<> after proxy<>?

Currently I get {?}{?}{?}

If I delete this one - stringify(const std::vector<T>& in) then the vector<int> starts getting called because it would be a specialization of the first.

Then I would get {?}INT vector specialization!{?}

Is there any way to call any of the 2 vector specialization stringification functions from proxy() - if they are defined last - after the proxy() function?

Is there a way to partially specialize on vector<> and still get called from proxy<>?

I don't want to specialize for vector<int>, vector<double>, vector<UserType>...

EDIT: forgot to mention I need this for C++98

Barry
  • 286,269
  • 29
  • 621
  • 977
onqtam
  • 4,356
  • 2
  • 28
  • 50

1 Answers1

3

First of all, avoid specializing function templates, prefer overloading. See Herb Sutter's article on the potential pitfalls.

Secondly, the issue you're running into involves how name lookup works for dependent names in function templates. Inside proxy<T>, stringify is a dependent name - it depends on T. That name will be looked up at the point of definition of the template (which will find stringify<T>(const T&) and not the other overload) and again at the point of instantiation in the associated namespace of the arguments (which would be std). Neither of those lookups find your other functions.

It's that second part of lookup - the argument-dependent lookup - that we can take advantage of. Let's just stick everything in one namespace (which I'm naming N arbitrarily, feel free to rename as appropriate):

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);
}

Ok, so far we've changed absolutely nothing. We still get {?} in all cases. But the now we can stick further overloads (not specializations) of stringify still in that namespace but after the definition of 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!";
    }
}

Those two overloads will be found by the second phase of the name lookup because N is an associated namespace of helper. Now proxy(intVFec) will find all three overloads of stringify instead of just the one. And now your code prints:

{?}INT vector overload!vector overload!

as desired. None of the above requires C++11.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • thanks a lot! you saved my ass! I love it when c++ magic works and I don't get it - still trying to NOT learn about ADL :) life is short. – onqtam Apr 29 '16 at 23:34
  • @onqtam ADL is pretty important - after all it's how `std::cout << "Hello, World!"` works! – Barry Apr 29 '16 at 23:38
  • just found out that this doesn't compile under VC++6... maybe ADL is broken (only when using templates for overloads! free function overloads are fine) - it says in ```proxy()``` that the call is ambiguous if there are more than 1 specializations. Maybe its time to drop support for it – onqtam Apr 29 '16 at 23:43
  • @onqtam It's not ADL that's broken, it's [VC++ that is](http://stackoverflow.com/q/6273176/2069064) – Barry Apr 29 '16 at 23:45
  • I hit that two-phase lookup problem a few days ago with the same stringification through the proxy function - and because of it I started making template specializations instead of just free function overloads - but now I can go back to free functions - yey! – onqtam Apr 29 '16 at 23:47