Reputation: 16242
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"}{}
Upvotes: 1
Views: 52
Reputation: 75688
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{};
}
Upvotes: 2
Reputation: 206567
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>();
};
Upvotes: 1
Reputation: 409166
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 };
Upvotes: 2