通过值传递所有类型,但字符串到模板函数

时间:2015-10-29 09:19:24

标签: c++ string templates pass-by-reference pass-by-value

我想定义一个模板函数,它为所有类型的值传递一个参数,但std::string(和const char*)。

template<typename T>
void foo( T value )
{
    // some code using value
}

std::string版本应该与template版本完全相同,但其参数的传递方式为const&

在不重复foo()的主体的情况下,做我想做的事情的最佳方法是什么?

我能想到的最好的方法是在另一个函数中使用value 包装代码,然后在foo()的所有版本中调用它({{1版本和template重载。还有另外一种方法吗?例如,是否可以在std::string重载内调用template版本?

修改

我想知道的是避免各种专业化和重载之间的代码重复的良好经验法则。什么是好的模式?我应该为body定义一个包装器函数,然后从所有重载/特化中调用它,还是有另一种方法?

5 个答案:

答案 0 :(得分:2)

简单解决方案:为std::string

提供重载
void foo( std::string const &value ) {
    // some code using value
}

答案 1 :(得分:2)

为了避免代码重复,可以扩展answer by 101010以实际从重载中调用模板:

#include <string>
#include <iostream>
#include <type_traits>
#include <boost/core/demangle.hpp>

template<typename T>
void foo( T value )
{
    std::cout << "inside template" << std::endl;
    std::cout << boost::core::demangle(typeid(value).name()) << std::endl;
}

void foo(const std::string &value)
{
    std::cout << "inside const string overload" << std::endl;
    foo<const std::string&>(value);
}
int main()
{
    foo(10);
    foo(std::string("hello"));
    return 0;
}

<强>输出

inside template
int
inside const string overload
inside template
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >

live example

答案 2 :(得分:1)

您可以定义类似于特征的类,它会将std::string转换为std::string&并保留所有其他类型的类型:

template<class T>
struct helper {
    typedef T type;
};

template<>
struct helper<std::string> {
    typedef std::string& type; // or const std::string& type if you want
};

template<typename T>
void foo( typename helper<T>::type value, T value2 )
{
    value = value2;
}

int main()
{
    int a = 10;
    foo(a, 42);
    std::cout << a << std::endl; // prints 10

    std::string s = "abc";
    foo(s, std::string("def"));
    std::cout << s << std::endl; // prints def
}

完整示例:http://coliru.stacked-crooked.com/a/96cf78e6c4846172

UPD:如@PiotrSkotnicki所述,只有一个参数会导致类型扣除失败。但是,我会保留答案,因为如果您确实有几个T类型的参数,或者您可以将显式模板参数指定为foo,那么它可能会有所帮助。

UPD2:要解决类型扣减问题,您可以添加另一个包装器:

template<typename T>
void foo_helper( typename helper<T>::type value )
{
    value = T();
}

template<typename T>
void foo(T& value)
{
    foo_helper<T>(value);
}

这仍然可能会有一些问题,因此这是否适用于您的用例,由您决定。

答案 3 :(得分:1)

我认为你要找的是C ++ 11中的rvalue signature。

简单如下:

#include <iostream>
#include <string>

template<typename T>
void foo(T&& value)
{
    std::cout << "was passed by refernece:" << std::is_lvalue_reference<T&&>::value << std::endl;  
    std::cout << value << std::endl;  
}

int main()
{
    std::string text = "hello";
    foo(text);
    foo(1);
}

您可以通过引用或值传递参数,并且rvalue规则将使用适当的类型。

答案 4 :(得分:0)

使用std::enable_if + std::is_convertibale

   template<typename T>
    typename std::enable_if<!std::is_convertible<T,std::string>::value>::type foo( T value )
    {
        // some code using value
    }