1

I have a template class that takes default member values.

template<class T = std::string>
struct A{
    T val = {"val"};
};

However sometimes the default values do not make sense, for example:

A<int> a1;  // cannot initialize int from "val"

Is there is good idiom to handle this issue?

I came up with this solution, which is quite verbose.

template<class T, class TT>
auto valid_or_default(TT&& other) -> 
decltype(T{std::forward<TT>(other)}){return T{std::forward<TT>(other)};}

template<class T>
auto value_of_default(...){return T{};}

template<class T = std::string>
struct A{
    T val = valid_or_default<T>("val");
};

(The other option is to set up a Boost.Fusion map to have a default value per type, but it is even more code and all the cases need to be handled.)


Update (thanks @Someprogrammerdude): Another alternative for very specific cases (no valid based on syntax) can be done by specializing the constructor:

template<class T = std::string>
struct A{
    T val;// = valid_or_default<T>("val");
    A() : val{}{}
};

template<> A<std::string>::A() : val{"val"}{}
alfC
  • 14,261
  • 4
  • 67
  • 118
  • Are you sure you want templates for this? Could it be solved through *specialization*? And what is the *actual* problem you need to solve? *Why* do you initialize a templated member variable with a fixed value? – Some programmer dude Aug 13 '18 at 22:30
  • @Someprogrammerdude, specializing member variable initialziation is doesn't seem to be a feature of the language: `template<> std::string A::val = "val";` gives `val is not a static member`. I could specialize the whole class (trying to avoid that). – alfC Aug 13 '18 at 22:34
  • @Someprogrammerdude, you are right, I can specialize the default constructor, but it is still not as powerful. See my edit. – alfC Aug 13 '18 at 22:39

3 Answers3

2

I still don't know what the original problem you try to solve is, or why you need to use a compile-time fixed-value for the initialization, but as it seems your structure is an aggregate you could simply use aggregate initialization:

template<typename T = std::string>
struct A
{
    T val;
};

// ...

A a = { "val" };
A<int> b = { 1 };
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
2

Here is a C++17 solution:

template<class T, class TT>
auto valid_or_default(TT&& other)
{
    if constexpr (std::is_constructible_v<T, TT>)
        return T{std::forward<TT>(other)};
    else
        return T{};
}
bolov
  • 72,283
  • 15
  • 145
  • 224
1

Here's another option.

template <typename T>
T get_default_value()
{
   return {};
}

template <> 
std::string get_default_value<std::string>()
{
   return "val";
}

template<class T = std::string>
struct A {
    T val = get_default_value<T>();
};
R Sahu
  • 204,454
  • 14
  • 159
  • 270