Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to approach explicit template instantiation in the presence of unpredictable type aliases?

I am attempting to add some extern template into my project, to speed up build times and reduce footprint on disk during build.

I've done so by listing specialisations that I use frequently, e.g.

extern template class std::vector<std::string>;
extern template class std::vector<unsigned int>;
extern template class std::vector<uint32_t>;
extern template class std::vector<size_t>;

The problem is that unsigned int is size_t, maybe, and uint32_t is unsigned int, maybe. So, depending on the build target, compilation fails for the "non-extern" variety of the list that actually instantiates the specialisations:

template class std::vector<std::string>;
template class std::vector<unsigned int>;
template class std::vector<uint32_t>;
template class std::vector<size_t>;

The error is like this (line and column number inaccurate):

templates-impl.h:15:36: error: duplicate explicit instantiation of ‘class std::vector<long unsigned int>’ [-fpermissive]
 template class std::vector<size_t>;

My goal is to just be able to list the types I use, as I use them, with a minimum of fuss and with no need to hardcode variants of the list for different targets.

I guess in C++14 I could solve this with an if constexpr and some std::is_same, at least if that were permitted at namespace scope.

How can I do it in C++11?

like image 510
Lightness Races in Orbit Avatar asked Dec 23 '17 20:12

Lightness Races in Orbit


People also ask

How do I instantiate a template function?

To instantiate a template function explicitly, follow the template keyword by a declaration (not definition) for the function, with the function identifier followed by the template arguments. template float twice<float>(float original); Template arguments may be omitted when the compiler can infer them.

Is it necessary to instantiate a template?

In order for any code to appear, a template must be instantiated: the template arguments must be provided so that the compiler can generate an actual class (or function, from a function template).

What is implicit instantiation?

Implicit instantiation means that the compiler automatically generates the concrete function or class for the provided template arguments. In general, the compiler also deduces the template arguments from the function's arguments. In C++17, the compiler can also deduce the template arguments for class templates.


2 Answers

Alternatively, you may have type-lists of to-be-instantiated types, of which only repeating types are replaced with dummy types (hopefully, to be optimized-out at link time).

In C++11, something like:

template<typename... V>
struct explicit_instlist
{
    template<int I>
    struct get
    {
        using VI = typename std::tuple_element<I,std::tuple<V...>>::type;

        using type = typename std::conditional< is_first_at<I,VI,V...>::value,
            VI, dummy_inst<I,VI> >::type;
    };
};

template<unsigned I>
using my_list = typename explicit_instlist<
    std::string,
    unsigned int,
    uint32_t,
    size_t
    >::template get<I>::type;

/*extern*/ template class std::vector< my_list<0> >;
/*extern*/ template class std::vector< my_list<1> >;
/*extern*/ template class std::vector< my_list<2> >;
/*extern*/ template class std::vector< my_list<3> >;

where dummy_inst<I,T> generates a unique dummy type to be used in place of T when already used, and is_first_at works like:

template<int I,typename T>
struct dummy_inst {};

template<int I,typename T,typename... V>
struct is_first_at {};

template<int I,typename T,typename V,typename... Vs>
struct is_first_at<I,T,V,Vs...>: std::conditional< std::is_same<T,V>::value,
    std::integral_constant<bool,I==0>,
    is_first_at<I-1,T,Vs...> >::type {};

clearly, dummy_inst will need to be specialized if the to be explictly instantiated template does not support the empty default. Something like boost preprocessor may be used to avoid explictly 'iterating' the explicit instantations and write a macro accepting the type list directly ...

like image 183
Massimiliano Janes Avatar answered Oct 13 '22 11:10

Massimiliano Janes


How about drop the unsigned int and size_t specializations and just make them all size-based?

extern template class std::vector<uint8_t>;
extern template class std::vector<uint16_t>;
extern template class std::vector<uint32_t>;
extern template class std::vector<uint64_t>;
like image 20
SoronelHaetir Avatar answered Oct 13 '22 11:10

SoronelHaetir