如何使用模板处理多类型变量?

时间:2017-07-16 17:00:49

标签: c++ c++11 templates c++17 template-meta-programming

无论yxx还是y,我都试图创建一个将int分配给std::string的函数。我写了这段代码:

#include <iostream>
#include <string>
#include <typeinfo>

template <typename T>
T& assign(T& x, T& y){

    if ( typeid(x).name() == "Ss" && typeid(y).name() == "Ss" ){
        std::string k = static_cast<std::string>(y);
        x = k;
        return x;
    }

else if ( typeid(x).name() == "i" && typeid(y).name() == "i" ){        
        int k = static_cast<int>(y);
        x = k;
        return x;
}

else{    
        std::cout << "uncorrect assignment" << std::endl;    
    }

}

int main(){

    std::string a = "empty_string";
    std::string b = "Hi there";
    assign(a, b);
    std::cout << a << std::endl;

}

但它不起作用。 它给出了错误:

[Error] invalid static_cast from type ‘std::basic_string<char>’ to type 

第14行:

 int k = static_cast<int>(y);

我无法理解,问题是什么?

我知道反对意见:我可能刚刚将函数赋值定义为:

template <typename T>
T& assign(T& x, T& y){
    x = y;    
}

哪个有效。但是,我正在研究另一个更复杂的功能,我必须(或者至少我没有找到任何方法)使用static_cast

所以,如果可以的话,请向我解释这个例子中的错误是什么,我可能会尝试修复我正在处理的功能。

非常感谢, 西蒙。

2 个答案:

答案 0 :(得分:2)

要做你想做的事,你需要C ++ 17和if constexpr。使用编译时工作的东西,而不是运行时的typeid

问题在于,使用您的代码typeid允许,运行时,选择代码的if或else部分,但编译器必须编译这两部分。所以必须编译

    int k = static_cast<int>(y);
    x = k;
Tstd::string

。这给出了错误。

你需要一个类型特征(例如std::is_same),它被评估为编译时,以及一个避免编译错误部分的构造。这个构造是if constexpr ( <test> )(其中<test>是有价值的编译时间),但不幸的是,它只能从C ++ 17中获得。

所以,在C ++ 17中你可以编写

template <typename T>
void assign (T & x, T const & y)
 {    
    if constexpr ( std::is_same<T, std::string>::value ) {
       std::string k = static_cast<std::string>(y);
       x = k;
    }
    else if constexpr ( std::is_same<T, int>::value ) {
       int k = static_cast<int>(y);
       x = k;
    }
    else {    
       std::cout << "uncorrect assignment" << std::endl;    
    }
}

但是,在C ++ 17之前,你必须遵循不同的方式。

答案 1 :(得分:0)

要在函数内单独处理不同的类型,可以选择将重载function call operators的本地struct定义为不同的类型:

#include <iostream>
#include <string>

template<typename T>
T& assign(T& x, const T& y) {
    struct {
        void operator()(std::string& lhs, const std::string& rhs) {
            std::cout << "Type is std::string." << std::endl;
            lhs = rhs;
        }
        void operator()(int& lhs, const int& rhs) {
            std::cout << "Type is int." << std::endl;
            lhs = rhs;
        }
    } assign_impl;

    assign_impl(x, y);
    return x;
}

int main() {
    /* Test No. 1 */ {
        std::string dest, src = "Foo";
        std::cout << "Test result: " << assign(dest, src) << std::endl;
    }

    /* Test No. 2 */ {
        int dest, src = 32;
        std::cout << "Test result: " << assign(dest, src) << std::endl;
    }
}

上面的代码适用于C ++ 98及更高版本,但它的缺点是,如果你尝试将它与未处理的类型一起使用,它会引发编译器错误。