2014-09-14 4 views
5

Я пытаюсь написать функцию, которая принимает несколько аргументов разных типов данных и возвращает сумму чисел. Он должен иметь возможность решить, какой тип данных будет использоваться для суммы. Напр. если я напишу add (3,1,2,3), он должен вернуть сумму как int. Однако, если я напишу add (3,1,2,5,3,25), он должен вернуть сумму как двойную.Добавление переменного числа чисел

Я пробовал использовать шаблон, но давал ошибку времени компиляции. Вот функция

template <typename T> 
T add(int n, ...) 
{ 
    T sum = 0; 
    va_list vl; 
    va_start(vl,n); 
    for(int i=0;i<n;i++) 
    { 
     sum += va_arg(vl,T); 
    } 
    va_end(vl); 
    return sum; 
} 
int main() 
{ 
    std::cout<<add(3,1,2,3); 
    return 0; 
} 

Compile Error: нет соответствия функции для вызова 'добавить (интермедиат, Int, Int, Int). Я думаю, что ошибка идет, потому что я прошел в va_arg T, но я не знаю, что еще передать, чтобы она была обобщена.

+4

Почему вы не используете [Шаблоны Varidaic] (http: // www.cplusplus.com/articles/EhvU7k9E/)? –

+0

Это решение проблемы, когда переданные аргументы являются целыми числами, но при передаче двойных значений он дает неверный ответ. –

+0

@ DarshilBabel нет, он работает. [** См. Его в прямом эфире **] (http://ideone.com/ggLxjO) – WhozCraig

ответ

-2

я думаю, что проблема вы определили тип параметра, как INT пытаются использовать

вместо: T Add (Int N, ...)

использования: T Add (T п, .. .)

+0

Я думаю, 'n' - это счет –

+0

n - это первое имя аргумента –

+0

@MohitJain Я бы заподозрил так, что не имеет смысла, если вы идете по шаблону вариационного шаблона, поскольку вы получаете его бесплатно с помощью' 'sizeof ...' ] (http: //en.cppreference.com/w/cpp/language/sizeof ...) и, при необходимости, немного математики. – WhozCraig

2

Вы должны заменить

std::cout<<add(3,1,2,3); 

с

std::cout<<add<int>(3,1,2,3); // explicitly, int, double, float whatever 

Чтобы код выполнялся успешно, поскольку компилятор не смог вывести имя типа из неявного вызова. Live code example here

Ваша функция возвращает значение типа T, но вы не указываете какой-либо аргумент типа T, что делает невозможным вывод этого типа компилятором.


Другое решение было бы добавить перегрузку, которая работает для add(0) и передать первый аргумент в оных типа T. Это может достичь цели неявного вычета OP. Теперь компилятор может выводить возвращаемый тип из первого аргумента.

#include <cstdarg> 
#include <iostream> 
#include <cassert> 
using namespace std; 

int add(int n) 
{ 
    assert(0 == n); 
    return 0; 
} 

template <typename T> 
T add(int n, T first, ...) 
{ 
    T sum = first; 
    va_list vl; 
    va_start(vl,first); 
    for(int i=1;i<n;i++) 
    { 
     sum += va_arg(vl,T); 
    } 
    va_end(vl); 
    return sum; 
} 
int main() 
{ 
    std::cout<<add(3,1,2,3); 
    std::cout<<add(3,1.5,2.,3.5); 
    return 0; 
} 

live code here

+0

Как я уже упоминал в комментарии к вопросу OP, это в значительной степени положило конец первоначальной цели определения возвращаемого типа во время выполнения. Размышляя об этом логически, нет способа сделать это (определить возвращаемый тип во время выполнения) без использования полиморфизма. –

+0

Одним из способов решения проблемы является перегрузка, которая работает для add (0), и передать первый аргумент в добавление типа T. Это может привести к цели неявного вычета OP. –

+0

Вы имеете в виду * писать * (не * правильно *) ... И я не вижу, как работает ваше предложение. Если вы думаете, что это так, то вы можете добавить его в ответ. –

2

Why don't you use Varidaic Templates ? – Mohit Jain

Если вы можете написать в C++ 14:

template<typename T> 
inline T sum(T t){ 
    return t; 
} 

template<typename T, typename... Ts> 
inline auto sum(T t, Ts... ts){ 
    return t+sum(ts...); 
} 

#include<iostream> 
int main(){ 
    std::cout<<sum(2.5, 2)<<'\n' 
      <<sum(2, 2.5)<<'\n' 
      <<sum(1u, 2.5, 3.f, '0')<<'\n'; 
} 

Если вы пишете в C++ 11 под MSVC++ (it doesn't work under g++):

template<typename T> 
inline T sum(T t){ 
    return t; 
} 

template<typename T, typename... Ts> 
inline auto sum(T t, Ts... ts)->decltype(t+sum(ts...)){ 
    return t+sum(ts...); 
} 

#include<iostream> 
int main(){ 
    std::cout<<sum(2.5, 2)<<'\n'   //works 
      <<sum(2, 2.5)<<'\n'   //works 
      <<sum(1u, 2.5, 3.f, '0')<<'\n';//works under VC++, but not under g++ 
} 
+1

Вы можете использовать 'std :: common_type'. (и принудительное продвижение поначалу может избежать некоторого * странного * результата для 'sum (int (42), char (127), char (127), char (2))' (42 вместо 298)). – Jarod42

+0

Только [при использовании 'std :: common_type' получил' 42' вместо '298'] (http://rextester.com/QNCHB76405). – GingerPlusPlus

+0

Другой пример с uint32_t vs uint64_t http://rextester.com/OKA3142 – Jarod42

Смежные вопросы