在科學計算的C++上有a great paper作者(T. Veldhuizen)建議基於特徵的處理地址類型提升的方法。我用這樣的方法,並發現它有效:Idiomatic C++ 11類型促銷
#include<iostream>
#include<complex>
#include<typeinfo>
template<typename T1, typename T2>
struct promote_trait{};
#define DECLARE_PROMOTION(A, B, C) template<> struct promote_trait<A, B> { using T_promote = C;};
DECLARE_PROMOTION(int, char, int);
DECLARE_PROMOTION(int, float, float);
DECLARE_PROMOTION(float, std::complex<float>, std::complex<float>);
// similarly for all possible type combinations...
template<typename T1, typename T2>
void product(T1 a, T2 b) {
using T = typename promote_trait<T1, T2>::T_promote;
T ans = T(a) * T(b);
std::cout<<"received "
<<typeid(T1).name()<<"("<<a<<")"<<" * "
<<typeid(T2).name()<<"("<<b<<")"<<" ==> "
<<"returning "
<<typeid(T).name()<<"("<<ans<<")"<<std::endl;
}
int main() {
product(1, 'a');
product(1, 2.0f);
product(1.0f, std::complex<float>(1.0f, 2.0f));
return 0;
}
輸出:
received i(1) * c(a) ==> returning i(97)
received i(1) * f(2) ==> returning f(2)
received f(1) * St7complexIfE((1,2)) ==> returning St7complexIfE((1,2))
由所屬類別返回類型的名稱是依賴於實現的;您的輸出可從礦,它使用GCC 4.7.2在OS不同X 10.7.4
在本質上,該方法定義了一個promote_trait
它簡單地含有一種類型定義:類型,其中兩個類型應該進行操作時,推動以給定的方式。我們需要宣佈所有可能的促銷活動。
當一個函數接收到這兩種類型時,它依靠promote_trait
來推導出結果的正確提升類型。如果某特定配對沒有定義特徵,則代碼無法編譯(一個理想特徵)。
現在,這篇論文是在2000年編寫的,我們知道C++在過去的十年裏有了很大的發展。那麼,我的問題如下:
有沒有一種現代的,習慣的C++ 11方法來處理類型提升與Veldhuizen引入的基於特徵的方法一樣有效?
編輯(使用std::common_type
)
基於呂克丹東的建議下,我創建了下面的代碼,它使用std::common_type
:
#include<iostream>
#include<complex>
#include<typeinfo>
#include<typeindex>
#include<string>
#include<utility>
#include<map>
// a map to homogenize the type names across platforms
std::map<std::type_index, std::string> type_names = {
{typeid(char) , "char"},
{typeid(int) , "int"},
{typeid(float) , "float"},
{typeid(double) , "double"},
{typeid(std::complex<int>) , "complex<int>"},
{typeid(std::complex<float>) , "complex<float>"},
{typeid(std::complex<double>) , "complex<double>"},
};
template<typename T1, typename T2>
void promotion(T1 a, T2 b) {
std::string T1name = type_names[typeid(T1)];
std::string T2name = type_names[typeid(T2)];
std::string TPname = type_names[typeid(typename std::common_type<T1, T2>::type)];
std::cout<<T1name<<"("<<a<<") and "<<T2name<<"("<<b<<") promoted to "<<TPname<<std::endl;
}
int main() {
promotion(1, 'a');
promotion(1, 1.0);
promotion(1.0, 1);
promotion(std::complex<double>(1), 1);
promotion(1.0f, 1);
promotion(1.0f, 1.0);
promotion(std::complex<int>(1), std::complex<double>(1));
promotion(std::complex<double>(1), std::complex<int>(1));
promotion(std::complex<float>(0, 2.0f), std::complex<int>(1));
return 0;
}
與輸出:
int(1) and char(a) promoted to int
int(1) and double(1) promoted to double
double(1) and int(1) promoted to double
complex<double>((1,0)) and int(1) promoted to complex<double>
float(1) and int(1) promoted to float
float(1) and double(1) promoted to double
complex<int>((1,0)) and complex<double>((1,0)) promoted to complex<int>
complex<double>((1,0)) and complex<int>((1,0)) promoted to complex<int>
complex<float>((0,2)) and complex<int>((1,0)) promoted to complex<int>
我很驚訝注意除了最後三次促銷之外的所有促銷都是我期望的。爲什麼要將complex<int>
和complex<double>
或complex<float>
提升爲complex<int>
!?
你熟悉'的std :: common_type'? –
@LucDanton:非常非常有用。然而,我很驚訝'std :: complex'和'std :: complex '和'std :: complex '之間的類型提升。任何見解? –
Escualo
這可能是由於'std :: complex'的主模板,並且說到:「實例化除float,double或long double之外的任何其他類型的模板複合的效果未指定。」 –