Zebrafish
Zebrafish

Reputation: 14406

How to conditionally include a statement based on its type in a template?

If an argument of int* or int () function can be passed to a template, how to do something different depending on which one was passed to the template?

#include <type_traits>


template <typename GetterType>
class Getter
{public: 
    using isInvokable = std::is_invocable<GetterType>;


    using GotValueType = typename std::conditional_t<isInvokable::value,
                                    std::invoke_result<GetterType>,
                                    std::remove_pointer<GetterType>>::type;

    Getter(GetterType a) : getter(a) {}

    GetterType getter;

    GotValueType get() {
        if constexpr (isInvokable::value) return getter();
        else return *getter;
        // EVEN THOUGH INT* ISN'T CALLABLE IT'S STILL TRYING TO CALL GETTER
        }

    
};

int main() 
{
    int a = 0;
    Getter getter(&a);
    getter.get();
}

It won't compile because it's trying to call the template argument type even though what I pass to it isn't callable. And it tries to return an int* instead of an int.

Edit: Is there a way to conditionally compile one thing or another? I thought constexpr was used for this sort of thing in templates.

Edit2: This won't compile on Visual Studio 19 with ISO C++ 17 Standard (std:c++17):

'return': cannot convert from 'int' to 'int *'  

Upvotes: 1

Views: 81

Answers (1)

rustyx
rustyx

Reputation: 85530

is_invocable and if constexpr are C++17 features. MSVC 2019 by default compiles in C++14 mode.

To enable C++17, configure the project to compile with /std:c++17 or /std:c++latest

msvc c++latest

The /std flag is supported since VS 2017.

Upvotes: 3

Related Questions