Использование специализации шаблона для различения значений и массивов (значений)

#c

#c

Вопрос:

Я пытаюсь сконструировать устройство, которое будет делать одно для значения (в частности, собственного типа) и другое для массива примитивов в стиле C.

Это то, что у меня есть сейчас, которое не делает того, что я хочу.

 #include <cstdlib>
#include <string>
#include <iostream>
#include <iomanip>

using namespace std;

template<class V> void dump_buf(const Vamp; val)
{
    cout << "val = " << val << "n";
}

template<class A> void dump_buf(const A ary[])
{
    cout << "ary size = " << sizeof(ary) << "n";
    for( size_t i = 0; i < sizeof(ary);   i )
        cout << "t" << i 1 << " : " << ary[i] << "n";
}

int main()
{
    cout << "n";
    int i = 42;
    float f = 3.14f;
    unsigned fib[] = {0,1,1,2,3,5};
    char s[] = "hello";
    dump_buf(i);
    dump_buf(f);
    dump_buf(s);
    dump_buf(fib);
}
  

Это не работает, потому что ary имеет тип pointer-to-something, а не array-of-something. Результат для вышеупомянутого (Intel, x64 compile, VS9) является:

 val = 42
val = 3.14
ary size = 8
        1 : h
        2 : e
        3 : l
        4 : l
        5 : o
        6 :
        7 : ╠
        8 : ╠
ary size = 8
        1 : 0
        2 : 1
        3 : 1
        4 : 2
        5 : 3
        6 : 5
        7 : 3435973836
        8 : 3435973836
  

Но я хочу, чтобы результат был:

 val = 42
val = 3.14
ary size = 6
        1 : h
        2 : e
        3 : l
        4 : l
        5 : o
        6 :
ary size = 6
        1 : 0
        2 : 1
        3 : 1
        4 : 2
        5 : 3
        6 : 5
  

Обратите внимание, что желаемый результат для строки составляет 6 символов, а не 5 из-за нулевого ограничителя, который является частью массива.

Есть ли какой-либо способ заставить это работать, используя только стандартный C и никаких дополнительных библиотек?

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

Комментарии:

1. Вместо массива в стиле c вы можете использовать std::valarray ( cplusplus.com/reference/std/valarray/valarray ) или std::vector ( cplusplus.com/reference/stl/vector ).

2. @yasouser: Тип входящих данных — массив в стиле C. Это не вариант.

3. @John-Dibling: В этом случае вы можете преобразовать массив либо в std::valarray, либо в std::vector. Если вы хотите использовать vector, то вы делаете: std::vector<int> v(fib, fib sizeof(myints) / sizeof(int)) . Если вы хотите использовать std::valarray, то: std::valarray<int> arr(fib, sizeof(myints) / sizeof(int)) .

4. @yasouser: или вы могли бы написать функцию, которая принимает ссылку на массив, и не выполнять никакого ненужного копирования.

Ответ №1:

Это должно сработать:

 template<class A, size_t S> void dump_buf(const A (amp; ary)[S])
{
    cout << "ary size = " << S << "n";
    for( size_t i = 0; i < S;   i )
        cout << "t" << i 1 << " : " << ary[i] << "n";
}
  

Принимая ссылку на массив, а не указатель на начало массива, размер известен и доступен в качестве предполагаемого аргумента шаблона.

Также помните, что это sizeof указывает размер в байтах, поэтому, когда вам действительно нужно количество объектов в массиве (и вы не можете или не хотите использовать подобный шаблон), вы хотите sizeof(ary)/sizeof(*ary) . В обоих случаях вам нужен реальный массив, а не указатель на массив, который потерял все знания о размере массива.