Reputation: 20103
Consider a class "myArbPrec" that can be initialised using
myArbPrec("0.1");
(e.g. it represents an arbitrary precision type).
I want my code to be compatible with both myArbPrec
and double
. The user sets the type with templates.
There are some constants in the template classes that are used in the program such as 0.1
. These constants are to be represented in the respective type the user chooses.
My question is: how do I put a constant in the code that is initialised depending on the type chosen? Specifically, for myArbPrec
, it should be initialised as myArbPrec("0.1")
. For double
, it should be initialised as double(0.1)
.
the problem is that I cannot use myArbPrec(0.1)
, since this converts first to double, potentially losing precision, and only then to myArbPrec
. Therefore, if my template argument is T
, I cannot write T(0.1)
. But because double("0.1")
is syntactically incorrect, I can also not use T("0.1")
.
So far, I tried to adapt this answer to my problem, by writing something like this:
template<typename T>
T atof(const char * c) {
if (typeid(T) == typeid(double))
return std::atof(c);
else
return T(c);
}
However, this fails because the else
branch is still compiled, even if typeid(T) == typeid(double)
is always false, which makes this to fail even when T
is double
.
Upvotes: 1
Views: 125
Reputation: 50540
As an alternative solution to the suggestion of @101010, you can use tag dispatching and overloaded functions:
#include<type_traits>
#include<utility>
#include<cstdlib>
#include<iostream>
template<typename>
struct tag {};
double atof(tag<double>, const char *c) {
std::cout << "double" << std::endl;
return std::atof(c);
}
template<typename T>
T atof(tag<T>, const char * c) {
std::cout << "something else" << std::endl;
return T{c};
}
template<typename T>
T atof(const char * c) {
return atof(tag<std::decay_t<T>>{}, c);
}
int main() {
atof<double>("3.1");
atof<std::string>("bar");
}
Upvotes: 0
Reputation: 3607
I think with C++17, you will be able to use your original template with an if constexpr
and that would work.
The proposed paper is here.
I don't have a compiler to test that with.
Upvotes: 0
Reputation: 42899
Use mutually exclusive SFINAE overloads of your atof
function:
namespace foo {
template<typename T>
typename std::enable_if<std::is_same<T, double>::value, T>::type atof(const char * c) {
return std::atof(c);
}
template<typename T>
typename std::enable_if<!std::is_same<T, double>::value, T>::type atof(const char * c) {
return T(c);
}
}
Upvotes: 3