简体   繁体   中英

How can I combine return type deduction, template instantiation with header files?

I would like to combine return type deduction and explicit template instantiation (eg f<int> instead of template<typename T> f<T> ). The example below shows how this can be done in one file play with code .

#include <type_traits>
#include <iostream>
#include <string>

enum Enum { String, Int };

template <Enum E>
auto f();

template <>
auto f<Enum::String> () {
   return "string";
}

template <>
auto f<Enum::Int> () {
    return 2;
}

int main()
{
    const Enum e = Enum::String;
    auto a = f<e>();
    const Enum g = Enum::Int;
    auto b = f<g>();

    return 0;
}

Question: How can I combine return type deduction, template instantiation with header files?

What I would like:

// f.hpp
template<Enum E> auto f();
// f.cpp
f<Enum::Int> f() { // ...
// other_file.cpp
#include "f.hpp"
auto a = f<Enum::Int>();

Error: function 'f<Enum::Int>' with deduced return type cannot be used before it is defined .

Ideas:

IMO the error makes sense since the function instantiation is not in the header and was thus not included in other_file.cpp .

I am unable to write the instantiations in the f.hpp since they are instantiations (obviously).

I thought about using inline , but that did not help (why?).

Can anyone help me?

I thought about using inline, but that did not help (why?).

regarding the inline keyword here:

// f.hpp
template<Enum E> auto f();

https://en.cppreference.com/w/cpp/language/definition

There can be more than one definition in a program of each of the following: class type, enumeration type, inline function, inline variable (since C++17), templated entity (template or member of template, but not full template specialization)

in short, you dont need inline for templates (unless its a full specialization)

in this case:

// f.cpp
f<Enum::Int> f() { // ...

you would need the inline keyword if this was in a header file. For ODR purposes this full specialization is basically treated as a function definition. Although since this definition is only in one cpp file, there is only one definition anyway so the inline keyword doesn't help.

for more info on inline with templates see also: https://stackoverflow.com/a/17667265/11429904

Actually, the 2 definitions you provide for f are called explicit specializations . You cannot define them in a dedicated implementation file because the compiler must know their return type.

In this situation a possible work around, if you want to use deduced return type, is to pack the specialization definition within the primary template definition using a constexpr if statement, and then use explicit template instantiation :

Inside f.hpp :

enum Enum { String, Int };

template <Enum E>
auto f(){
    if constexpr (E==String)
       return "string";
    else
       return 2;
}

extern template
auto f<Enum::String> ();

extern template
auto f<Enum::Int> ();

Inside f.cpp :

#include "f.hpp"
template
auto f<Enum::String> ();

template
auto f<Enum::Int> ();

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