下面的運行很好:
#include <iostream>
#include <string>
/**。
* 簡單地列印引數的值并根據其型別調整
*根據其型別調整陳述句。
*/
template<typename T>
int function(T value){
if(std::is_same<T,double> () || std: :is_same<T,float>() ){
std::cout << value << ", type is float" << std::endl;
return 0。
}
else if(std::is_same<T,std::string> ()){
std::cout << value << ", type is string"/span> << std::endl;
return 0;
}
else if(std::is_same<T,char*> () || std: :is_same<T,const char*>() ){
std::cout << value << ", type is char*"/span> << std::endl;
return 0。
}
else{
std::cout << "不支持的資料型別" << std::endl;
return 1;
}
}
int main(){
function<double>(1.2345) 。
函式<std::string>("Hello World")。
const char* sentence = "Hello World"。function<const char*>(sentence)。
return 0;
}
由于這個運行沒有任何問題,我試著改變了下面這一行:
std::cout << value << " , type is string" << std::endl;
to
std::cout << value.c_str() << ", type is string"/span> << std::endl;
然而,這并不能編譯。這就像在編譯.c_str()呼叫時定義了value的型別。然而,我本以為value引數的型別只取決于模板引數T。為什么在這種情況下沒有編譯呢?
產生以下錯誤:
在'int的實體化中。 type">int function(T) [with T = double] '。
.cpp:321:25: 需要從這里開始。
錯誤:請求for'value'中的成員'c_str',它不屬于class type 'double'
std::cout << value.c_str() << ", type is string" << std::endl。
~~~~~~^~~~~
在'int function(T)的實體化中。 params">(T) [with T = const char*] '。
.cpp:323:70: 需要從這里開始。
. cpp:306:22: 錯誤。request for member 'c_str' in 'value', which is of nonclass type 'const char*'
uj5u.com熱心網友回復:
在你的原始代碼中,你實際上沒有使用value的任何成員,所以它的型別與if陳述句的主體相當不相關。 你只是依靠 operator<< 多載來 "做正確的事情"。
然而,一旦你開始訪問value的成員,它的型別就與你的代碼非常相關。
例如,讓我們來看看您的第一個測驗案例,double。 編譯器將不會實體化你所期望的函式的版本:
int function<double> (double value){
std::cout << value << ", type is float" << std::endl;
return 0。
它將INSTEAD實體化你的這個版本的函式:
int function<double> (double value){
if(std::is_same<double,double> () || std: :is_same<double,float>()){ /true
std::cout << value << ", type is float" << std::endl;
return 0。
}
else if(std::is_same<double,std::string>()){ / false
std::cout << value.c_str() << ",型別是字串" << std::endl。
return 0;
}
else if(std::is_same<double,char*> () || std: :is_same<double,const char*>()){ // false
std::cout << value << ", type is char*" << std::endl;
return 0。
}
else{
std::cout << "不支持的資料型別" << std::endl;
return 1;
}
你的std::string和const char*測驗案例也將實體化類似的版本。 而不是你所期望的那些。
這是因為你的函式在運行時創建std::is_same的實體,并呼叫其bool轉換運算子,所以所有這些if都是運行時檢查,因此它們的分支在編譯時必須包含有效的代碼,以便在運行時執行。沒有任何分支能夠在編譯時被消除。而且由于double和const char*沒有c_str()成員,你會得到你所看到的錯誤。
現在,你可能想通過用std::is_same<T,...>()代替std::is_same<T,...>:value或std::is_same_v<T,...>來避免這種運行時行為,這些都是編譯時常量。 而你這樣做也是半正確的:
template<typename T>。
int function(T value){
if(std::is_same_v<T,double> || std::is_same_v<T,float>) {
//if(std::is_same<T,double>:value || std::is_same<T, float>:value){
std::cout << value << ", type is float"/span> << std::endl;
return 0。
}
else if(std::is_same_v<T,std::string> ){
//else if(std::is_same<T,std::string>:value){
std::cout << value.c_str() << ",型別是字串" << std::endl。
return 0;
}
else if(std::is_same_v<T,char*> || std: :is_same_v<double,const char*>){
//else if(std::is_same<T,char*> :value || std::is_same<double,const char*> :value){
std::cout << value << ", type is char*" << std::endl;
return 0。
}
else{
std::cout << "不支持的資料型別" << std::endl;
return 1;
}
這將簡化為,例如double:
int function<double> (double value){
if(true){
std::cout << value << ", type is float" << std::endl;
return 0。
}
else if(false){
std::cout << value.c_str() << ",型別是字串" << std::endl。
return 0;
}
else if(false){
std::cout << value << ", type is char*" << std::endl;
return 0。
}
else{
std::cout << "不支持的資料型別" << std::endl;
return 1;
}
然而,編譯器仍然需要完全評估每個if分支內的代碼,因此每個分支仍然需要包含有效的代碼,即使編譯器能夠在評估其代碼后優化掉任何未使用的分支。 而在這種情況下,value.c_str()對于沒有c_str()成員的T型別,仍然是無效的代碼。
為了解決這個問題,你需要使用if constexpr,它將執行編譯時檢查,并在評估其代碼之前消除未使用的分支,例如:
template<typename T>
int function(T value){
if constexpr (std: :is_same_v<T,double> || std::is_same_v<T,float>()){
std::cout << value << ", type is float" << std::endl;
return 0。
}
else if constexpr (std::is_same_v<T,std::string>){
std::cout << value.c_str() << ",型別是字串" << std::endl。
return 0;
}
else if constexpr (std:: is_same_v<T,char*>| std::is_same_v<T,const char*>){
std::cout << value << ", type is char*" << std::endl;
return 0。
}
else{
std::cout << "不支持的資料型別" << std::endl;
return 1;
}
現在,編譯器將能夠按照你所期望的那樣實體化你的函式:
int function< double>(double value){ // and float.
std::cout << value << ", type is float" << std::endl;
return 0。
}
int function<std::string>(std::string value){
std::cout << value.c_str() << ",型別是字串" << std::endl。
return 0;
}
int function<const char*> (const char* value){
std::cout << value << ", type is char*"/span> << std::endl;
return 0。
}
template<typename T>
int function(T value){
std::cout << "不支持的資料型別" << std::endl;
return 1;
uj5u.com熱心網友回復:
感謝@Igor Tandetnik建議使用constexpr和@Lala5th強調他的建議。
該函式應該看起來像:
template<typename T>
int function(T value){
if constexpr (std: :is_same<T,double>() || std::is_same<T,float>()){
std::cout << value << ", type is float" << std::endl;
return 0。
}
else if constexpr(std::is_same<T,std::string>()){
std::cout << value.c_str() << ",型別是字串" << std::endl。
return 0;
}
else if constexpr(std: :is_same<T,char*> () || std: :is_same<T,const char*>() ){
std::cout << value << ", type is char*"/span> << std::endl;
return 0。
}
else{
std::cout << "不支持的資料型別" << std::endl;
return 1;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/314148.html
標籤:
