0

I have a deserialisation function. With templates, I'd like to be able to get the thing that I'm deserialising. In other words, I'd like a function that computes the serialised thing and another that handles deserialisation. If I name them differently, I have no problem, and, indeed, this is so easy a solution that I will surely just do that. But it bothers me that I don't understand why the following isn't acceptable.

#include <string>

using std::string;

// In real life, fetch the stringified object.
template<>
string foo(int x);

// In real life, fetch an object and deserialize it.
template <typename T>
T foo(int x) {
    string s = foo<string>(x);
    T t;
    // Do something with s.
    return t;
}

template<>
string foo(int x) { return std::to_string(x); }

Compiling with

clang -Wall -Wextra -std=c++14 foo.cc -o foo

says

foo.cc:6:8: error: no function template matches function template specialization 'foo'
string foo(int x);

So the obvious solution is just to change the first function to string make_foo(int x) and be done with it.

To help me learn, I've been trying to understand why what I wrote above fails. Note that I also tried template <> string foo<string>(int x), though I would think that the specialisation could be inferred.

jma
  • 3,580
  • 6
  • 40
  • 60
  • Is that your complete code? How do you use these functions? Can you create a [Minimal, Complete, and Verifiable Example](http://stackoverflow.com/help/mcve) and show us? And is that the complete output from the compiler? There's nothing else? – Some programmer dude Nov 23 '15 at 10:53
  • Yes, this was complete. Unless you were hoping I'd bring in a bunch of protobuf code to show how I was doing deserialisation. ;-) – jma Nov 23 '15 at 11:03
  • That said, your comment on declaration order was spot on, and that solved the problem. (That, and re-adding the to avoid an inference error.) If you'd like to provide that as an answer, I'd be happy to accept it. – jma Nov 23 '15 at 11:04

2 Answers2

2

The compiler needs to see the generic declaration before you can declare a specialization, so simply change the order of the declarations.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • I accepted this because it led me to the solution. In fact, "remove" is excessive: it suffices to change the order of the two declarations! – jma Nov 23 '15 at 11:12
1

The specialization can't be inferred here because the return type of a function is not part of the function declaration. Thus, if no function parameter type depends on the template parameter, you have to write the full specialization:

template<>
std::string foo<std::string>(int x)
{
   /* ... */
}

For instance, in the following case, you can let the compiler infer the specialization:

template<class T>
void f(T arg)
{
    // generic case
    /* ... */
}

template<>
void f(bool arg)
{
    // bool case
    /* ... */
}
YSC
  • 38,212
  • 9
  • 96
  • 149
  • I had indeed tried that, `template<> string foo(int x)`, but the compiler complains: extraneous `template<>`, and then it thinks I'm declaring a `string foo` followed by a missing `;`. – jma Nov 23 '15 at 11:00