调用函数,如果有,则忽略

问题描述:

我现在想要制作模板,它将一些元素推送到向量和其他类型,支持push_back运算符。调用函数,如果有,则忽略

我能做到这样

template<typename T> 
T fill(size_t n) { 
    T v; 
    //(1) 
    for(size_t i = 0; i < n; ++i){ 
     v.push_back(generate_some_how()); 
    } 
    return v; 
} 

它的工作原理。但是现在我想用v.reserve(n);而不是(1)来提高支持它的类型的速度。但我想仍然能够编译此代码的类型不会编译reserve

这是实现这一点的简单方法吗?

我知道我可能专注于硬编码类型,但它似乎并不好。

C++ 11是可以的。

+0

我怀疑它,但我不确定。我的猜测是你将不得不使用模板专门化 – 2013-03-08 20:05:34

+4

不太难......你需要编写一个特征来检测具有正确签名的'reserve'成员函数的存在。有了这个工具,你可以使用不同的方法,你可以编写一个'reserve_'模板函数,使用这个特性分派给'reserve()'或者一个no-op的调用,并从//调用它)'或者你可以在助手或者'fill'中使用SFINAE。我会尝试使用辅助函数,因为'fill'中的大部分代码都是相同的。 – 2013-03-08 20:07:00

+0

如果您使用的是C++ 11,请考虑支持适当的'emplace'调用来替换'push_back'。 – 2013-03-08 20:20:41

一个简单的例子:

template<class T> 
auto maybe_reserve(T& v, size_t n, int) 
    -> decltype(v.reserve(n), void()) 
{ 
    v.reserve(n); 
} 

template<class T> 
void maybe_reserve(T&, size_t, long){} 

template<typename T> 
T fill(std::size_t n) { 
    T v; 
    maybe_reserve(v, n, 0); 
    for(size_t i = 0; i < n; ++i){ 
     v.push_back(generate_some_how()); 
    } 
    return v; 
} 

Live example.有关解释,看一看here

+0

C++ 03版本也是可能的,尽管更加复杂和限制。 – Xeo 2013-03-08 20:20:13

+0

没有编译后''resize''保留''deque' [ideone](http://ideone.com/e7p8fv) – RiaD 2013-03-08 20:29:02

+0

@RiaD:这是GCC 4.7的一个问题。 Clang 3.2和GCC 4.8正常工作。 GCC的bug可以通过将第一个重载的返回类型改为'decltype(v.reserve(n),void())'来解决。 – Xeo 2013-03-08 20:34:56

不太难....你需要写一个特征来检测预留成员函数的存在与正确的签名。使用该工具有不同的方法,您可以编写一个reserve_模板函数,使用该特性分派到reserve()的调用或no-op并从// (1)调用它,或者您可以在帮助程序中使用SFINAE或fill本身。我会尝试使用辅助函数,因为填充中的大部分代码都是相同的。

检测是否void reserve(std::size_t)构件函数存在于C++ 03:使用C++ 11

template <typename T> 
struct has_reserve { 
    typedef char yes; 
    typedef yes no[2]; 
    template <typename U, U> struct ptrmbr_to_type; 
    template <typename U> 
    static yes& test(ptrmbr_to_type<void (T::*)(std::size_t),&U::reserve>*); 
    template <typename U> static no& test(...); 
    static const bool value = sizeof(test<T>(0))==sizeof(yes); 
}; 

在C++ 11的一个可能的方法:

template<typename T, typename = void> 
struct reserve_helper 
{ static void call(T& obj, std::size_t s) { } }; 

template<typename T> 
struct reserve_helper<T, decltype(std::declval<T>().reserve(0), void(0))> 
{ static void call(T& obj, std::size_t s) { obj.reserve(s); } }; 

template<typename T> 
T fill(std::size_t n) 
{ 
    T v; 
    reserve_helper<T>::call(v, 10); 
    for(std::size_t i = 0; i < n; ++i){ 
     v.push_back(generate_somehow()); 
    } 

    return v; 
} 

这里是一个live example表示该呼叫到reserve()被简单地与没有定义任何reserve()构件功能的UDT跳过。

+0

需要'reserve'返回'void'(是的,通常情况下,我知道)。 – Xeo 2013-03-08 20:21:44

+0

@Xeo:好的,好吧:)让我编辑 – 2013-03-08 20:22:43

+1

你试过编译和运行这个吗? :3 – Xeo 2013-03-08 20:27:30