tags:

views:

292

answers:

4

I have an interface

std::string
get_string(Source const &s, std::string const &d);
int
get_int(Source const &s, int const &d);
bool
get_bool(Source const &s, bool const &d);

which I'd like to change to

template<class T>
T
get(Source const &s, T const &d);

But there's no sensible base template, so the actual base definition is a legal but useless (return d;). What can I do to force compile-time failure if the base is instantiated? Is there an idiomatic solution for this situation?

+8  A: 

Don't define the template, just declare it and define the three specializations.

template <typename T>
T get(Source const &, T const &);

template<>
std::string get(Source const &s, std::string const &d) {
    return d + s.stringval(); // or whatever
}

[Edit: removed stuff about overloads - just for once, template function specialization does actually seem to be better. Who woulda thunk?]

Steve Jessop
implicit conversions are the reason to go for a template
just somebody
Do you mean the caller is expected always to specify the type, rather than ever allowing it to be inferred from the parameters?
Steve Jessop
I mean that I want the selected function to exactly match actual types
just somebody
... and no conversions on the values passed to the selected function
just somebody
Oh, I get it. For example if you define it with overloads and call `get(Source(), "hello")`, you get the bool version of the function, which probably isn't what you wanted. If you define it with templates and do the same, you get an error because there's no template instantiation for that char array type.
Steve Jessop
@Steve Jessop: exactly. thank you for the excellent answer BTW: no ugly hack, fails with a clear error message (not before link time though, which is a small minus; oh well).
just somebody
A: 

Declare the baseclass (t) as abstract, that way an instance can never be created of that class.

the question is about free functions, not classes
just somebody
+3  A: 

just do

string get(source, string);
int get (source, int);
bool get(source, bool);
pm100
that opens a can of worms since `bool` and `int` are implicitly convertible back and forth.
just somebody
It'll be fine, the compiler won't implicitly convert them when the correct unconverted overload is available.
Terry Mahaffey
A: 

If you are willing to pay for run-time polymorphism, you can do this...

template <typename T>
class Interface
{
   virtual T get(Source const &s, T const &d) = 0;
};

class StringInterface : public Interface<std::string>
{
   virtual std::string get(Source const& s, std::string const& d);
};

// etc.

Since your base is an abstract class, you will get a compile-time failure if you try to instantiate it directly.

JohnMcG