Reputation: 4402
I have functions of this type:
type uniRndtype()
{
return typeValue;
}
and now I'm trying to wrap them inside another template function like this:
template<typename T>
T(* uniRndType(void))()
{
if (is_same<T, bool>::value)
{
return uniRndBool;
} else if (is_same<T, char>::value)
{
return uniRndChar;
} else
...
}
and calling it like this:
uniRndType<int>();
But I'm getting an error: "error: return value type does not match the function type" because each return has a different type..
I there a way to make it work? Because from a runtime point of view I see no errors, only the compiler have problems.
Upvotes: 1
Views: 4955
Reputation: 10417
template <typename T> T (*uniRndType())()
{
//else
...
}
template <> bool (*uniRndType())()
{
return uniRndBool;
}
template <> char (*uniRndType())()
{
return uniRndChar;
}
That's all.
edit: In principle, we must do like @Angew. but it's little troublesome
Upvotes: 1
Reputation: 16685
Compiler needs to know what types will be used by functions/methods at compile time. At this point you must instantiate this template function with types which it may receive as template parameter, like @ikh wrote here.
But, if you are using template class with template methods, you have 2 ways:
1) Simply write realization of each template method in .h file (right in the place where you declaring template class body) instead of prototypes only;
2) Or after declaring prototypes in .h file you need to instatiate this template class with template parameters which it may receive.
Upvotes: 0
Reputation: 171097
The problem is that while the optimiser can eliminate dead code branches, the front-end (lexical, syntactic & semantic analysis) can't. Which means all code in a template instantiation must be valid. That is, even though in this:
if (is_same<T, bool>::value)
{
return uniRndBool;
}
the body will never be executed when T
is char
, it must still be valid C++ code. And of course it's not, because uniRndBool
doesn't have the correct type.
You have two options: a hackish one which works in your particular case, and a generic one.
The hackish one is using reinterpret_cast<T(*)()>
in all the return
statements. For the correct T
brach, it will be a no-op. The other branches will never be executed at runtime, so all will be fine.
The other solution is to use template specialisation. Since it's a bad idea to specialise function templates, you could use the well-known "delegate to class" trick:
template <class T>
struct uniRndTypeHelper;
template <>
struct uniRndTypeHelper<bool>
{
static bool (*get())() { return uniRndBool; }
};
template <>
struct uniRndTypeHelper<char>
{
static char (*get())() { return uniRndChar; }
};
template<typename T>
T(* uniRndType(void))()
{
return uniRndTypeHelper<T>::get();
}
Upvotes: 3
Reputation: 62472
This won't work because when the compiler expands the template method for a given type the method has to be valid. Your type, T, needs to be compatible with all the return types listed, eg bool
, char
, etc. As I mentioned in the comments, if you passed in a std::string
you wouldn't expect the method to work, would you?
One way around this is to use template specialization to indicate what you want for each type.
Upvotes: 0