how to provide a default value for a template conditional type?

Viewed 87

All

I am writing a trimStart fucntion with c++ template like the following:


template<typename T>
static T trimStart(T source, std::conditional<isWide<T>(), const wchar_t*, const char*>::type trimChars = " \t\n\r\v\f"))
{
    ....
}

now I like to provide a default value " \t\n\r\v\f" or L" \t\n\r\v\f" according the type of trimChars, could you please help me look at how to implement for that?


With the great help from 463035818_is_not_a_number & Philipp, I look at the latest template docs again, here is the updated skeleton of code (C++20):

//limit to T as string only
    template<typename T>
    concept isStr = (
        std::is_same_v<T, std::string> ||
        std::is_same_v<T, std::wstring>
        );
// different default value according type of T
    template<typename T>
    constexpr auto defaultValue() {
        if constexpr (std::is_same_v<T, std::wstring>)
            return L" \t\n\r\v\f";
        else
            return " \t\n\r\v\f";
    }

//claim a function parameter with a default value
    template<isStr T>
    static T trimStart(T source, decltype(defaultValue<T>()) trimChars = defaultValue<T>())
        {
              //...internal variable example 
         typename std::conditional<some_conditional<T>(), std::wistringstream,std::istringstream>::type 
            ss(...);

        }
2 Answers

It should be possible to use different constants conditionally by using template specialization as sketched in this answer. You can create different classes and put separate compile time constants (or runtime functions) in them. At compile time, you select which one should be chosen (e.g. by specializing them with a boolean).

In C++17, you have constexpr if, which would simplify it. But since the question is tagged with C++14, I assume you cannot use it.

I rearranged your code to this:

#include <type_traits>
#include <iostream>

template <typename T> struct is_foo : std::false_type {};
struct foo{ int value;};
template <> struct is_foo<foo> : std::true_type {};

struct bar{};


template <typename T>
void func(T t, std::conditional_t<is_foo<T>::value,int,double> x = ????) {
    std::cout << x << "\n";
}

int main() {
    func(foo{});
    func(bar{});
}

func takes a parameter of type T. Depending on a condition on this type the second argument type is decided among two types. In my code it is between int when is_foo<T> is true and double when is_foo<T> is false.

You can replace ?? with a call to a function template that returns the desired default argument:

template <typename T,typename = void>
struct get_default{ 
    double operator()(){ return 4.2;}
};

template <typename T>
struct get_default<T,std::enable_if_t<is_foo<T>::value>> {
    double operator()(){ return 42; }
};

Demo

In your specific case I would consider to simply use std::string<T>.

Related