2016-07-29 2 views
0

Я пытаюсь создать вспомогательный метод createTypedArray, который «знает», сколько байтов на элемент выделяется. То есть createTypedArray<Float32Array>(size), а не createTypedArray<Float32Array, 4>(size).Создание специализированных шаблонов с помощью макроса

Это лучший подход, который я придумал. Есть ли лучший подход? Есть фиктивный первичный шаблон, который мне не нравится, по крайней мере.

#define TYPED_ARRAY_P(T, bytesPerElement)           \ 
    template <>                  \ 
    Local<T> createTypedArray<T>(size_t size) {          \ 
    size_t byteLength = size * bytesPerElement;          \ 
    Local<ArrayBuffer> buffer = ArrayBuffer::New(Isolate::GetCurrent(), byteLength); \ 
    Local<T> result = T::New(buffer, 0, size);          \ 
    return result;                 \ 
    } 

// Dummy 
template <typename T> 
Local<T> createTypedArray(size_t s) { 
    return void; 
} 

TYPED_ARRAY_P(Uint8Array, 1); 
TYPED_ARRAY_P(Uint16Array, 2); 
TYPED_ARRAY_P(Uint32Array, 4); 

#undef TYPED_ARRAY_P 
+1

Er, почему бы вам просто не использовать 'sizeof (T)'? – GManNickG

+0

@GManNickG, к сожалению, это 1 для всех типов. (Float32Array и друзья из v8 - я не могу этого контролировать.) – ZachB

+1

Yikes, это некоторые плохо разработанные классы. Там даже нет никаких typedefs или констант или функций или чего-либо для получения размера элемента. Я бы предложил сделать что-то вроде 'template struct V8ArrayToElementSize;' и специализировать его для каждого типа массива, например 'template <> struct V8ArrayToElementSize {static constexpr value = 1; }; '. Затем вы можете использовать свою одну функцию и заменить 'bytesPerElement' на' V8ArrayToElementSize :: value'. – GManNickG

ответ

2

Обычно вы хотели бы использовать sizeof(ElementType), такие как:

auto buffer = AllocateSomeBuffer(numberOfElements * sizeof(ElementType)); 

Вы не работаете с ElementType напрямую, хотя, но вместо некоторого представления типа массива. Не беспокойтесь, нам просто нужно получить ElementType из вашего T.

К сожалению, эти классы, похоже, имеют что-то вроде T::value_type или T::element_size или что-то действительно. Тем не менее, нам все равно хотелось бы иметь «гарантированное» сопоставление между T и его размером элемента, и каждый раз вытаскивать некоторые магические константы.

Обычное решение таких проблем, как «характерные черты». Это специализации классов, которые дают нам некоторую вычисленную информацию о типе. В нашем случае, мы хотим что-то вроде этого:

template <typename T> 
struct V8TypeTraits; // no generic case (e.g. can't ask for V8 traits about int) 

template <> 
struct V8TypeTraits<Uint8Array> { 
    typedef std::uint8_t value_type; 
}; 

// etc. 

Теперь мы можем получить ElementType:

template <typename T> 
Local<T> createTypedArray(size_t elementCount) { 
    const size_t byteLength = 
     elementCount * sizeof(typename V8TypeTraits<T>::value_type); 
    // etc. 
    return result; 
} 

Очевидно, что вы не должны делать value_type, вы могли бы вместо того, чтобы поместить static constexpr element_size = /* whatever */; в ваших черт и использования :

const size_t byteLength = 
     elementCount * V8TypeTraits<T>::element_size; 

Но отображение в value_type кратчайший путь обратно в C++ земли (например, было бы излишним имеют как value_type, так и element_size, а первый - более общий, поэтому я выбираю этот).

+0

MSVC компилируется без жалобы, но с GCC мне пришлось написать 'sizeof (typename V8TypeTraits :: value_type)'. (Не уверен, что это потому, что я использую 'float', а не' std :: float_t', но я не хочу, чтобы 'FLT_EVAL_METHOD' влиял на эти typedef.) Еще раз спасибо. – ZachB

+0

@ZachB: Упс, моя ошибка. GCC здесь верен. В моем первоначальном примере проекта использовался элемент 'element_size', который является значением и не нуждается в' typename'. Но когда тип зависит от расширения шаблона, вы должны сообщить компилятору, что результатом этого будет тип с использованием 'typename'. В этом отношении MSVC несовместим. Хороший улов. – GManNickG

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