简体   繁体   中英

c++ return template function

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.

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

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM