Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I partial compile a template function in C++

Tags:

c++

templates

I have a function to determine whether a template type is pointer.

template<class T>
struct is_pointer_struct { static const bool value = false; };

template<class T>
struct is_pointer_struct<T*> { static const bool value = true; };

template<class T>
bool is_pointer(T &var) {
    return is_pointer_struct<T>::value;
}

And I have a initialize function.

template<class T>
void initialize(T &val) {
    if (is_pointer(val))
        val = NULL;
    else
        val = T();
}

Obviously, when T is string, this code can't be compiled. Is there a way that compile val = NULL when T is pointer type and compile val = T() when T is not a pointer type?

like image 353
Howard Avatar asked Jul 10 '17 09:07

Howard


People also ask

Are templates runtime or compile-time?

All the template parameters are fixed+known at compile-time. If there are compiler errors due to template instantiation, they must be caught at compile-time!

Are template functions always inline?

The template function must be inline and visible, typically this is all done in the header file. You wouldn't normally place the code in a . cpp file to be compiled as a separate module.

What is the rule of compiler by templates?

The compiler usually instantiates members of template classes independently of other members, so that the compiler instantiates only members that are used within the program. Methods written solely for use through a debugger will therefore not normally be instantiated.

Are templates compiled?

The template repository stores template instances between separate compilations so that template instances are compiled only when necessary. The template repository contains all nonsource files needed for template instantiation when using the external instances method.


2 Answers

In your particular case you could just use uniform initialization, as VTT said:

val = T{};

Also, the Standard Library provides std::is_pointer.


As an answer to the more general question "how do I branch at compile-time?":

  • In C++17, all you have to do is change your if(...) to if constexpr(...):

    template<class T>
    void initialize(T &val) {
        if constexpr(is_pointer(val))
            val = nullptr;
        else
            val = T();
    }
    
  • In C++14, you can implement your own static_if.

  • In C++03/11, you could use tag dispatching:

    template <typename T>
    void initialize_impl(std::true_type /* pointer */, T& val)
    {
        val = NULL;
    }
    
    template <typename T>
    void initialize_impl(std::false_type /* non-pointer */, T& val)
    {
        val = T();
    }
    
    template<class T>
    void initialize(T &val) { initialize_impl(std::is_pointer<T>{}, val); }
    
like image 95
Vittorio Romeo Avatar answered Sep 20 '22 12:09

Vittorio Romeo


The right way to do the things in your case is to use uniform initialization, as it is mentioned.

As an option, you might make use of SFINAE based on your type trait so the necessary template will be instantiated (here is a C++ 11 way to do that):

template<class T>
auto initialize(T &val) ->
    typename std::enable_if<is_pointer_struct<T>::value>::type {
        val = nullptr;
}

template<class T>
auto initialize(T &val) ->
    typename std::enable_if<!is_pointer_struct<T>::value>::type {
        val = T();
}
like image 34
Edgar Rokjān Avatar answered Sep 17 '22 12:09

Edgar Rokjān