是否可以在C ++中使用模板化的单参数求和函数?

时间:2016-06-16 00:47:42

标签: c++ templates sum generic-programming

在python中,我们可以这样做:

int_list = [1, 2, 3, 4, 5]
print(sum(int_list)) # prints 15
float_tuple = (1.2, 3.4, 9.9)
print(sum(float_tuple)) # prints 14.5

sum函数接受任何可迭代的元素,这些元素知道如何相互添加到0并产生总和。

我想在C ++ 11中创建一个相同的函数。我知道存在accumulate方法,但我想要一个带有单个参数的函数。基本上,我想知道如何编译以下代码:

#include <string>
#include <iostream>
#include <vector>
#include <deque>
#include <list>

template<typename iterable>
auto sum(iterable iterable_) {
    auto it = iterable_.begin();
    auto end = iterable_.end();
    if (it == end) {
        return 0;
    }
    auto res = *(it++); 
    while (it != end) {
        res += *it++;
    }
    return res;
}

int main() {
    std::vector<int> int_vector = {0, 1, 2, 3, 4, 5}; 
    std::cout << sum(int_vector) << '\n';    // prints 15
    std::deque<int> int_deque = {4, 5, 7};
    std::cout << sum(int_deque) << '\n';     // prints 16
    std::list<float> float_list = {1.2, 3.4, 9.9};
    std::cout << sum(float_list) << '\n';    // should print 14.5, but produces error.

}

此代码几乎有效。问题是auto在iterable为空的情况下看到return 0;,并且假定函数必须返回int。然后它看到float版本返回float并且它会混淆。有没有办法告诉编译器,如果return float(0)后来发现return返回float,请说@interface AppDelegate () <UITabBarControllerDelegate> @property (nonatomic, strong) PDFDocumentStore *documentStore; @property (nonatomic, strong) DocumentListViewController *documentsViewController; @property (nonatomic, strong) DocumentListViewController *recentViewController; @property (nonatomic, assign) BOOL launchingWithURL; @property (nonatomic, assign) BOOL addSkipBackupAttributeToItemAtURL; @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [self migrateIfNeeded]; UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard_iPhone" bundle:nil]; UIViewController *rootViewController = [storyboard instantiateViewControllerWithIdentifier:@"Login"]; [[UIApplication sharedApplication].keyWindow setRootViewController:rootViewController]; self.documentStore = PDFDocumentStore.new; [self.documentStore.rootFolder load]; UITabBarController *tabBar = (UITabBarController *)[[self window] rootViewController]; tabBar.delegate = self; self.documentsViewController = (DocumentListViewController *)[tabBar.viewControllers[0] topViewController]; FolderDocumentListViewModel *folderModel = [[FolderDocumentListViewModel alloc] initWithFolder:self.documentStore.rootFolder]; self.documentsViewController.viewModel = folderModel; [self.documentsViewController view]; self.recentViewController = (DocumentListViewController *)[tabBar.viewControllers[1] topViewController]; RecentDocumentListViewModel *recentModel = [[RecentDocumentListViewModel alloc] initWithDocumentList:self.documentStore.documentList]; self.recentViewController.viewModel = recentModel; NSString *pdf = @"2016 Product Handbook"; NSString *toPath = [[[NSFileManager grt_documentsPath] stringByAppendingPathComponent:pdf] stringByAppendingPathExtension:@"pdf"]; [self addSkipBackupAttributeToItemAtURL:[NSURL fileURLWithPath:toPath]]; NSURL *URL = [launchOptions objectForKey:UIApplicationLaunchOptionsURLKey]; if (URL) { self.launchingWithURL = YES; } return YES; }

3 个答案:

答案 0 :(得分:5)

是的,你可以至少为标准容器做这项工作。

标准容器为存储在该容器中的值类型定义名为value_type的类型别名。对于空容器,您可以返回此类型的值构造对象:

template<typename iterable>
auto sum(iterable const &iterable_) {
    auto it = iterable_.begin();
    auto end = iterable_.end();
    if (it == end) {
        return typename iterable::value_type();
    }
    auto res = *(it++); 
    while (it != end) {
        res += *it++;
    }
    return res;
}

这取决于所包含的类型是默认构造的,但这可能不是一个主要问题(当然适用于intfloat等原始类型。

答案 1 :(得分:5)

如果您想要使用任何 C ++ 11范围(即,您可以在基于范围的表达式中迭代的任何内容 - 包括数组以及具有免费的容器) beginend),我们可以添加一些使用声明并换行std::accumulate

template <class Range>
auto sum(Range&& range) {
    using std::begin;
    using std::end;
    using T = std::decay_t<decltype(*begin(range))>;

    return std::accumulate(begin(range), end(range), T{});
}

如果您不想包装accumulate,那么您也可以重新实现该循环以执行相同的操作。

答案 2 :(得分:2)

以下方法即使对非标准容器也适用;只要某些内容以合理的方式实现channelbegin()

end()