Jorge Leitao
Jorge Leitao

Reputation: 20103

How to use if else along with type initialisation in c++?

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

Answers (3)

skypjack
skypjack

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

ghlecl
ghlecl

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

Dimitrios Bouzas
Dimitrios Bouzas

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

Related Questions