I am writing a templated function that can take a std::optional
or a arithmetic type as the argument. The function then needs to select the underlying type and convert a string to the underlying arithmetic type or the arithmetic type.
#include <optional>
#include <cstdint>
#include <string>
#include <type_traits>
template<typename T, typename F = std::conditional_t<std::is_arithmetic_v<T>,
T,
typename T::value_type>>
void convertNumericColumn(std::string &column, T &value)
{
if (!column.empty())
{
try
{
// value = boost::lexical_cast<F>(column); // Only commented out to ensure the code compiles.
}
catch(...){}
};
}
int main(int, char **)
{
std::string value = "123";
std::optional<std::uint64_t> test1;
std::uint64_t test2;
convertNumericColumn(value, test1); // Compile OK
convertNumericColumn(value, test2); // Does not compile.
}
https://godbolt.org/z/9vfsK1oqr
The errors are error: no matching function for call to 'convertNumericColumn(std::string&, uint64_t&)' and error: 'long unsigned int' is not a class, struct, or union type
The problem is that you are using std::conditional_t
and passing T
which doesn't have value_type
i.e. long unsigned int
doesn't have value_type
, so the compilation fails. T
must have a value_type
as per your code else it fails with the error you get.
Instead you can use if constexpr
like this:
#include <optional>
#include <cstdint>
#include <string>
#include <type_traits>
#include <iostream>
#include <boost/lexical_cast.hpp>
template<typename T>
void convertNumericColumn(std::string &column, T &value)
{
if (!column.empty())
{
try
{
if constexpr (std::is_arithmetic_v<T>)
{
value = boost::lexical_cast<T>(column);
}
else
{
value = boost::lexical_cast<typename T::value_type>(column);
}
}
catch(...){}
};
}
int main(int, char **)
{
std::string value = "123";
std::optional<std::uint64_t> test1;
std::uint64_t test2;
convertNumericColumn(value, test1);
convertNumericColumn(value, test2);
std::cout << test1.value() << ' ' << test2 << '\n';
}