2015-06-20 2 views
1

я следующий код:Умножение определяемые пользователем массивы в C++

#include <iostream> 
#include <array> 

typedef std::array<int, 2> eval_t; 
eval_t operator*(eval_t e1, eval_t e2) { return {e1[0] * e2[0], e1[1] * e2[1]}; } 

int main() 
{ 
    eval_t a = {1, 2}; 
    eval_t b = a * {2, 1}; 
    std::cout << "b = (" << b[0] << ',' << b[1] << ')' << std::endl; 
} 

GCC отказался составить мое умножение:

$ g++ -std=c++11 test.cc 
test.cc: In function ‘int main()’: 
test.cc:10:17: error: expected primary-expression before ‘{’ token 
    eval_t b = a * {2, 1}; 
       ^

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

Вместо этого, если я пишу:

eval_t a = {1, 2}; 
eval_t v = {2, 1}; 
eval_t b = a * v; 

это работает.

+1

Ваш оператор даже не берет 'eval_t' для его умножения, но Clang дает ясную ошибку независимо: * ошибка: список инициализаторов не может использоваться в правой части оператора '\ *' * – chris

ответ

3

std::array представляет собой агрегат, и он не имеет конструктора принимающую std::initializer_list в качестве аргумента, как и другие контейнеры, поэтому программа не может создать eval_t из initializer_list. Таким образом, компилятор не может найти соответствующий тип перегруженной функции оператора, поэтому он не удался.

По этой причине {1, 2} не может быть неявно преобразован в eval_t, как вы ожидали.

Чистые исходные инициализаторы не допускаются с бинарными операторами в соответствии со стандартом, поэтому компилятор отклонит его. Но это разрешено в заявлениях о возврате. Более подробно объясняются в этом ответе: Initializer lists and RHS of operators

Если изменить заявление следующим образом, он будет работать

eval_t b = a * eval_t{{2, 1}}; 
+0

решение правильное, но причина неверна. Логические инициализаторы не допускаются в качестве операндов к функциям оператора. http://stackoverflow.com/questions/11420448/initializer-lists-and-rhs-of-operators – 0x499602D2

2

Просто ошибка синтаксиса. Исправьте линию.

return{ { e1[0] * e2[0], e1[1] * e2[1] } }; 

и

eval_t b = a * eval_t{ { 2, 1 } }; 

Тест:

#include <iostream> 
#include <array> 

typedef std::array<int, 2> eval_t; 
eval_t operator*(eval_t e1, eval_t e2) 
{ 
    return{ { e1[0] * e2[0], e1[1] * e2[1] } }; 
} 

int main() 
{ 
    eval_t a = { 1, 2 }; 
    eval_t b = a * eval_t{ { 2, 1 } }; 
    std::cout << "b = (" << b[0] << ',' << b[1] << ')' << std::endl; 
    // b = (2,2) 

} 
+0

Спасибо. Это работает. Но уверены ли вы, что дополнительные брекеты полезны? – lucasart

+0

Да. Это правильный синтаксис для компиляторов, которые не поддерживают C++ 0x. Для недавних компиляторов с C++ 0x 'eval_t {1,2} {}' должен выполнять ту же работу. –

+1

@jafar: если компилятор не поддерживает C++ 11, ему не понравятся фигурные скобки для конструкторов * вообще * (или даже 'std :: array', для чего это важно) ... –

0

Вы могли бы также рассмотреть вопрос о том, что вместо определения собственных перегружен operator*, чтобы воспользоваться стандартной библиотекой:

std::array<int, 2> a = {1, 2}; 
std::array<int, 2> b = {2, 1}; 
std::array<int, 2> c; 
std::transform(a.begin(), a.end(), b.begin(), c.begin(), std::multiplies<int>()); 

LIVE DEMO

+1

Да, это также возможно. Плохой вкус, хотя: слишком многословный и слишком медленный. – lucasart

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