2016-07-26 80 views
1

考虑一类“myArbPrec”,可以使用被初始化如何在C++中使用if和else类型初始化?

myArbPrec("0.1"); 

(例如它代表一个任意精度的类型)。

我希望我的代码兼容myArbPrecdouble。用户使用模板设置类型。

在程序中使用的模板类中有一些常量,例如0.1。这些常数将以用户选择的相应类型表示。

我的问题是:如何根据选择的类型在代码中初始化一个常量?具体来说,对于myArbPrec,应该初始化为myArbPrec("0.1")。对于double,应该初始化为double(0.1)

的问题是,我不能使用myArbPrec(0.1),因为这种转换第一翻一番,可能会丢失精度,然后才myArbPrec。因此,如果我的模板参数是T,我不能写T(0.1)。但是因为double("0.1")在语法上不正确,所以我也不能使用T("0.1")

到目前为止,我努力去适应this answer我的问题,通过写这样的事情:

template<typename T> 
T atof(const char * c) { 
    if (typeid(T) == typeid(double)) 
     return std::atof(c); 
    else 
     return T(c); 
} 

然而,失败的原因是else分支仍然编译,即使typeid(T) == typeid(double)始终是假的,这使得即使在Tdouble时也会失败。您atof功能

+0

除了答案,你可以期待C++ 17,其中'如果constexpr'是一个存在的东西,例如:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0292r1.html –

回答

3

使用互斥SFINAE重载:

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); 
    } 
} 
+0

对'std :: atof'的使用是AFAIK disencouraged,更好的使用'std :: strtof'(或者甚至是'std :: stof'作为字符串) – Superlokkus

+3

@Superlokkus'使用std :: atof是AFAIK disencouraged':嗯,请你发布消息来鼓励这种阻止。 – 101010

+1

OSX/FreeBSD手册页:https://www.freebsd.org/cgi/man.cgi?query=atof&apropos=0&sektion=3&manpath=FreeBSD+10.3-RELEASE+and+Ports&arch=default&format=html和开放组: http://pubs.opengroup.org/onlinepubs/9699919799/functions/atof.html 如果你阅读C标准,你至少可以找到一个实际的理由:当结果不能被表示时,它们调用UB,相反, st(r)xx家族。 – Superlokkus

0

我想用C++ 17,你将能够与if constexpr使用原来的模板,并会工作。

拟议论文是here

我没有一个编译器来测试。

+1

http://melpon.org/wandbox/permlink/L8NPsPi4eiKMCeaO – 101010

0

作为一种替代解决方案的@ 101010,你可以使用tag分派的建议和重载函数:

#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"); 
}