How to pass a 2 dimensional float array from QML to C++? - arrays

I have a two dimensional float array in QML. How do I get its values in C++.
I have created a class in c++ and have done the part of qmlRegisterType. The class is now accessible in QML.
Please demonstrate with a small example.
Here's what I have tried:
Header:
#include <QQuickItem>
#include <iostream>
class Controller : public QObject
{
Q_OBJECT
Q_PROPERTY(QList <QVariantList> names READ names WRITE setnames NOTIFY namesChanged)
QList <QVariantList> m_names;
public:
Controller()
{
}
~Controller() {
}
QList <QVariantList> names() const
{
return m_names;
}
public slots:
void setnames(QList <QVariantList> arg)
{
QVariantList p;
if (arg.size () > 0)
{
p = arg.first ();
std::cout << "\narg: \n" << p[0].toInt ();
}
else
std::cout << "\nqqqq " << arg.size () << "\n";
}
signals:
void namesChanged(QList <QVariantList> arg);
};
qml
import QtQuick 2.0
import FromCpp 1.0
Rectangle
{
property variant arras: [[1,2,3], [4,5,6]]
Controller
{
id: ppp
}
MouseArea
{
anchors.fill: parent
onClicked:
{
ppp.setnames(arras)
console.log(arras.length)
}
}
}
The exact output from QtCreator:
Starting /home/***/documents/test/build-junk-Desktop_Qt_5_1_0_GCC_64bit-Debug/junk...
QML debugging is enabled. Only use this in a safe environment.
2
qqqq 0
QThreadStorage: Thread 0x181e270 exited after QThreadStorage 2 destroyed
/home/***/documents/test/build-junk-Desktop_Qt_5_1_0_GCC_64bit-Debug/junk exited with code 0
///
Here, as you can see the size of the 2D array from QML is printed correctly as 2 and the size is printed 0 from c++.
Why is that happening? Please explain.

According to user1095108's answer, in order to access the internal elements of the QML's 2 Dim array passed to C++, we need to convert each row to a list as follows:
QML part:
import QtQuick 2.0
import FromCpp 1.0
Rectangle
{
property variant twoDimArray: [[1,2,3], [4,5,6]]
Controller
{
id: controllerA
}
MouseArea
{
anchors.fill: parent
onClicked:
{
controllerA.setname (twoDimArray)
}
}
}
C++ part:
void setname (QVariantList arg)
{
if (arg.size())
{
QList <QVariant> p = arg[0].toList();
std::cout << "\nRow0 0:" << p[0].toInt ();
std::cout << "\nRow0 1:" << p[1].toInt ();
std::cout << "\nRow0 2:" << p[2].toInt ();
std::cout << "\n";
QList <QVariant> p1 = arg[1].toList();
std::cout << "\nRow1 0:" << p1[0].toInt ();
std::cout << "\nRow1 1:" << p1[1].toInt ();
std::cout << "\nRow1 2:" << p1[2].toInt ();
}
}
Output:
Starting /home/.../documents/test/build-junk-Desktop_Qt_5_1_0_GCC_64bit-Debug/junk...
QML debugging is enabled. Only use this in a safe environment.
Row0 0:1
Row0 1:2
Row0 2:3
Row1 0:4
Row1 1:5
Row1 2:6/home/.../documents/test/build-junk-Desktop_Qt_5_1_0_GCC_64bit-Debug/junk exited with code 0

It is actually very simple. Javascript arrays map to QVariantLists, Javascript objects to QVariantMaps. Therefore, you are dealing with nested QVariantLists. Try this:
void setnames(QVariantList const& arg)
{
if (arg.size())
{
auto const p(arg.front().toList());
std::cout << "\narg: \n" << p.front().toInt();
}
else
std::cout << "\nqqqq " << arg.size () << "\n";
}

This is my method :
#include <QQuickItem>
#include <QDebug>
#include <QVariantList>
class Controller : public QObject
{
Q_OBJECT
Q_PROPERTY(QVariant names READ names WRITE setnames NOTIFY namesChanged)
QVariant m_names;
public:
Controller()
{
}
~Controller() {
}
QVariant names() const
{
return m_names;
}
public slots:
void setnames(QVariant arg)
{
QVariantList dim1 = arg.toList();
qDebug() << "outer dimension size" << dim1.size();
for(int i=0;i<dim1.size();++i)
{
QVariantList &dim2 = dim1.at(i).toList();
qDebug() << "inner dimension size at" << dim2.size();
}
}
signals:
void namesChanged();
};

Try this:
Somewhere in QML file:
property variant floats: [1.1, 2.2, 3.3, 4.4, 5.5, 6.6]
Includes:
#include <QtQuick/QQuickView>
#include <QQmlContext>
#include <QQmlProperty>
#include <QQuickItem>
In C++, in constructor for example:
QQuickView *view = new QQuickView();
QWidget *container = QWidget::createWindowContainer(view, ui->widget);//I show view in my widget
container->setMinimumSize(ui->widget->size());
container->setMaximumSize(ui->widget->size());
view->setSource(QUrl::fromLocalFile("pathToQMLFile"));
//starts here
QQmlProperty property(view->rootObject(), "floats");//get rootObject and set name of property
QVariantList lst = property.read().toList();//use raed method to get QVariant and convert it to list
for (int i = 0; i < lst.length(); ++i)
{
qDebug() << lst.at(i).toFloat();//show list
}
Output:
1.1
2.2
3.3
4.4
5.5
6.6
I hope my code shows main idea and you can use it in your class, because the most important job(how to get numbers) was done.

It looks like you can use QVariantList (or QList<QVariant>):
#include <QtQuick>
class Controller : public QObject
{
Q_OBJECT
Q_PROPERTY(QVariantList names READ names WRITE setnames NOTIFY namesChanged)
QVariantList m_names;
public:
Controller()
{
}
~Controller() {
}
QVariantList names() const
{
return m_names;
}
public slots:
void setnames(QVariantList arg)
{
qDebug() << arg;
}
signals:
void namesChanged(QVariantList arg);
};
#include <QApplication>
int main(int argc, char** argv)
{
QApplication app(argc, argv);
qmlRegisterType<Controller>("FromCpp", 1, 0, "Controller");
QQuickView view(QUrl(QStringLiteral("main.qml")));
view.show();
return app.exec();
}
#include "main.moc"
Output:
(QVariant(QVariantList, (QVariant(int, 1) , QVariant(int, 2) , QVariant(int, 3) ) ) , QVariant(QVariantList, (QVariant(int, 4) , QVariant(int, 5) , QVariant(int, 6) ) ) )

Related

std::visit Vs For_each loop

Let the data structure be anything (Array, Vectors, Std::Variant). But what is the difference in traversing using just for/for_each against std::visit.
for (auto& Element: collection){
std::visit([](auto arg){std::cout << arg << " ";}, Element);
}
And
for_each(collection.begin(), collection.end(), [](Element& e)
{
std::cout << e;
});
Note1: I know C-style for loop vs C++ for_each..For_each avoids typo error/syntactic sugar. so we can be happy with just for_each.
Note2: I know visitor design pattern too, which will be used for polymorphic object against polymorphic behaviour.
But still I couldn't appreciate and understand std::visit.
And when I digged further, I came to know something called Overload pattern.
template<typename ... Ts>
struct Overload : Ts ... {
using Ts::operator() ...;
};
template<class... Ts> Overload(Ts...) -> Overload<Ts...>;
But this Overload pattern too can be done using the same for_each right?
Thanks in advance for the reply.,
The difference between your first and second method is that the second does not work if your collection elements are variants. The example below compiles and lists your options.
Methods 2 and 4 are the only elegant ones I believe. But Method 2 is limited (see how it prints) while Method 4 gives you all the flexibility you may wish for.
But this does not necessarily mean Method 4 is the way to go. Place some intentional errors in Method 4 and then look at the error messages. They are mostly unintelligible.
#include <iostream>
#include <utility>
#include <variant>
#include <vector>
#include <algorithm>
using Element = std::variant<int, std::string>;
using Collection = std::vector<Element>;
Collection c = {1, 2, "three", "four", 5};
auto print_int = [](int const & e)
{
std::cout << "int: " << e << std::endl;
};
auto print_str = [](std::string const & e)
{
std::cout << "string: " << e << std::endl;
};
auto print_any = [](auto && e)
{
std::cout << "element: " << e << std::endl;
};
void Method1 ()
{
for (Element const & e: c)
{
{
auto const * i = std::get_if<int>(&e);
if (i)
{
print_int(*i);
continue;
}
}
{
auto const * s = std::get_if<std::string>(&e);
if (s)
{
print_str(*s);
continue;
}
}
}
}
void Method2 ()
{
for (Element const & e: c)
{
std::visit(print_any, e);
}
}
void Method3 ()
{
std::for_each(c.cbegin(), c.cend(), [](Element const & e)
{
std::visit(print_any, e);
});
}
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
void Method4 ()
{
for (Element const & e: c)
{
std::visit(overloaded
{
[](int i) { print_int(i); },
[](std::string s) { print_str(s) ; }
}, e);
}
}
int main ()
{
std::cout << std::endl << "Method1" << std::endl;
Method1();
std::cout << std::endl << "Method2" << std::endl;
Method2();
std::cout << std::endl << "Method3" << std::endl;
Method3();
std::cout << std::endl << "Method4" << std::endl;
Method4();
}

How to have have function give out seperate card hands to seperate people

For a homework assignment i need to create a program that lets you play the Irish card game 25. I can kind of have my code give out a hand to one person but if i try to have multiple people, the code gives out an identical hand to the other people. How do i give different, unique hands to other people?
I've tried using a loop, thinking that the function would simply reset the array but it hasn't
/* Deals a random hand of cards */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define TRUE 1
#define FALSE 0
#define BOOL int
#define NUM_SUITS 4
#define NUM_RANKS 13
int DealCards(int i);
int main()
{
int i;
int NumOfPlayers;
printf("Please Enter the Number Of Players: ");
scanf("%d", &NumOfPlayers);
for (i = 1; i <= NumOfPlayers; i++)
{
DealCards(i);
}
}
int DealCards(int i)
{
BOOL in_hand[NUM_SUITS][NUM_RANKS] = { FALSE };
int num_cards = 5, rank, suit;
const char rank_code[] = { '2', '3', '4', '5', '6', '7', '8',
'9', '10', '11', '12', '13', 'A' };
const char suit_code[] = { 'C', 'D', 'H', 'S' };
srand(time(NULL));
printf("\n\nPlayer %d's hand :\n", i);
while (num_cards > 0)
{
suit = rand() % NUM_SUITS;
rank = rand() % NUM_RANKS;
if (!in_hand[suit][rank])
{
in_hand[suit][rank] = TRUE;
num_cards--;
printf(" %cof%c ", rank_code[rank], suit_code[suit]);
}
printf("\n");
}
return 0;
}
The problem is that you call srand() function before giving card to every player. You use time(NULL) as an argument, therefore seed changes only every second, and players get cards with the same seed.
You need to set seed only once for each program launch.
Your current method is drawing cards with replacement, then checking if that has been drawn. It's rather easy, and a better model of the game, to shuffle the deck.
What you should do is define a type that encodes a particular card, populate a collection of that type, with each card value in use, shuffle the deck, then assign cards from the shuffled deck.
As a sketch
#include <vector>
#include <string>
#include <random>
#include <algorithm>
#include <iostream>
const std::vector<std::string> rank_code = { "2","3","4","5","6","7","8","9","10","Jack","Queen","King","Ace" };
const std::vector<std::string> suit_code = { "Clubs","Diamonds","Hearts","Spades" };
const int num_cards = 5;
struct Card
{
Card(char s, char r) : suit(s), rank(r) {}
char suit;
char rank;
};
std::ostream & operator<< (std::ostream & os, const Card & c)
{
return os << rank_code[c.rank] << " of " << suit_code[c.suit];
}
using Deck = std::vector<Card>;
Deck freshDeck()
{
Deck result;
for (std::size_t s = 0; s < suit_code.size(); ++s)
for (std::size_t r = 0; r < rank_code.size(); ++r)
result.emplace_back(s, r);
return result;
}
void dealCards(int player, Deck & deck)
{
std::string joiner;
std::cout << std::endl << "Player " << player << "'s hand" << std::endl;
for (int c = 0; c < num_cards; ++c)
{
std::cout << joiner << deck.back();
deck.pop_back();
joiner = ", ";
}
std::cout << std::endl;
}
int main ()
{
std::mt19937 gen{ std::random_device{}() };
Deck deck = freshDeck();
std::shuffle(deck.begin(), deck.end(), gen);
std::cout << "Enter number of players" << std::endl;
int num_players;
std::cin >> num_players;
for (int p = 1; p <= num_players; ++p)
{
dealCards(p, deck);
}
}
Just initialize your srand(time(NULL)) before giving cards
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define TRUE 1
#define FALSE 0
#define BOOL int
#define NUM_SUITS 4
#define NUM_RANKS 13
int DealCards(int i);
int main()
{
int i;
int NumOfPlayers;
printf("Please Enter the Number Of Players: ");
scanf("%d",&NumOfPlayers);
//here for example
srand(time(NULL));
for (i = 1; i <= NumOfPlayers; i++)
{
DealCards(i);
}
}
int DealCards(int i) {
BOOL in_hand[NUM_SUITS][NUM_RANKS] = { FALSE };
int num_cards = 5, rank, suit;
const char rank_code[] = { '2','3','4','5','6','7','8',
'9','10','11','12','13','A' };
const char suit_code[] = { 'C','D','H','S' };
printf("\n\nPlayer %d's hand :\n",i);
while (num_cards > 0) {
suit = rand() % NUM_SUITS;
rank = rand() % NUM_RANKS;
if (!in_hand[suit][rank])
{
in_hand[suit][rank] = TRUE;
num_cards--;
printf(" %cof%c\n", rank_code[rank], suit_code[suit]);
}
}
return 0;
}
The problem is that the srand is initialized with the same value each time it is run.
So the same random values are generated in the same order. This is why all the hands are the same.
srand and rand are from the <cstdlib> header.
In C++11 and higher it is better to use functions from <random> header.
Also C++ gives many possibilities to use object orientated programming and has an extensive library of data structures and algorithms. I would suggest to use std::vector or std::array instead of plain arrays. And also use std::shuffle to get a random order of cards.
#include <vector>
#include <string>
#include <random>
#include <algorithm>
#include <iostream>
#include <exception>
//////////////////////////////////////////////////////////////////////////////////////////
class Rank
{
std::string value;
Rank(std::string value) : value(value) {}
public:
static const std::vector< Rank >& get_all()
{
static std::vector< Rank > suits = { { "2" }, { "3" }, { "4" }, { "5" }, { "6" },
{ "7" }, { "8" }, { "9" }, { "10" }, { "J" },
{ "Q" }, { "K" }, { "A" } };
return suits;
}
const std::string& to_string() const { return value; }
};
//////////////////////////////////////////////////////////////////////////////////////////
class Suit
{
std::string value;
Suit(std::string value) : value(value) {}
public:
static const std::vector< Suit >& get_all()
{
static std::vector< Suit > ranks = {
{ "Clubs" }, { "Diamonds" }, { "Hearts" }, { "Spades" }
};
return ranks;
}
const std::string& to_string() const { return value; }
};
//////////////////////////////////////////////////////////////////////////////////////////
class Card
{
Suit suit;
Rank rank;
public:
Card(const Suit& suit, const Rank& rank) : suit(suit), rank(rank) {}
std::string to_string() const { return rank.to_string() + " of " + suit.to_string(); }
};
//////////////////////////////////////////////////////////////////////////////////////////
class Deck
{
std::vector< Card > cards;
public:
Deck()
{
const auto& ranks = Rank::get_all();
const auto& suits = Suit::get_all();
cards.reserve(ranks.size() * suits.size());
for (const Suit& s : suits)
for (const Rank& r : ranks)
cards.emplace_back(s, r);
}
void shuffle()
{
static std::random_device rd;
static std::mt19937 g(rd());
std::shuffle(cards.begin(), cards.end(), g);
}
std::size_t cards_count() const { return cards.size(); }
Card get_top_card()
{
if (cards_count() == 0)
throw std::logic_error("No more cards!");
const auto card = cards.back();
cards.pop_back();
return card;
}
};
//////////////////////////////////////////////////////////////////////////////////////////
int get_player_count()
{
std::cout << "Please enter the number of players:" << std::endl;
int player_count;
std::cin >> player_count;
return player_count;
}
//////////////////////////////////////////////////////////////////////////////////////////
void deal_cards(int player_count, int cards_to_deal, Deck& deck)
{
for (auto player_num = 1; player_num <= player_count; player_num++)
{
std::cout << "\n\nPlayer " << player_num << "'s hand :\n";
for (auto card_count = 0; card_count < cards_to_deal; card_count++)
{
if (deck.cards_count() == 0)
{
std::cout << "\n\nNo more cards to deal!" << std::endl;
return;
}
std::cout << deck.get_top_card().to_string() << ", ";
}
}
std::cout << std::endl;
}
//////////////////////////////////////////////////////////////////////////////////////////
int main()
{
Deck deck;
deck.shuffle();
const auto player_count = get_player_count();
const auto cards_to_deal = 5;
deal_cards(player_count, cards_to_deal, deck);
}
//////////////////////////////////////////////////////////////////////////////////////////

Simulate click on Windows Froms ToolStrip button in another process

I've found the handle of a Windows Forms ToolStrip in another application.
(Window name is toolStrip1, class name is WindowsForms10.Window.8.app.0.378734a.)
Is there any way to enumerate the child buttons, find a button by caption and simulate a button click? The buttons are not child windows, so EnumChildWindows doesn't work.
Simulating a mouse click with constant coordinates on the ToolStrip itself is not a very good option as the available buttons and button captions may change.
As #Jimi suggested, the solution is to use the UI Automation Windows API. I've managed to find the button by going down in the UI automation tree of UI elements from the desktop window to the given element, matching the names of elements. Then I called Invoke on it to simulate a click.
Here my a highly unstructured "C-style" C++11 test code for demonstration purposes, in case anyone else finds it useful. You will need to link to ole32.lib and oleaut32.lib.
#include <iostream>
#include <UIAutomation.h>
bool GetChildElementByName(IUIAutomationElement * * Child,
IUIAutomationElement * Parent,
const wchar_t * Name, IUIAutomation * UIAut);
int main(int argc, char * argv[])
{
// Initialize COM
switch ( CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED) )
{
case S_OK:
break;
case S_FALSE:
CoUninitialize();
// fall through
default:
std::cout << "CoInitializeEx error.\n";
return 1;
}
// Create a CUIAutomation object and query IUIAutomation interface
IUIAutomation * uiautomation;
if ( CoCreateInstance(CLSID_CUIAutomation, nullptr, CLSCTX_INPROC_SERVER,
IID_IUIAutomation, reinterpret_cast<LPVOID *>(&uiautomation)) != S_OK )
{
std::cout << "CoCreateInstance error.\n";
CoUninitialize();
return 1;
}
// Get the desktop UI element
IUIAutomationElement * desktop;
if ( uiautomation->GetRootElement(&desktop) != S_OK )
{
std::cout << "GetRootElement error.\n";
uiautomation->Release();
CoUninitialize();
return 1;
}
// Find a button element in a window inside a toolstrip.
IUIAutomationElement * elem;
// Fix memory leak...
if
(
!GetChildElementByName(&elem, desktop, L"Thermo Scientific LabWriter V4.6", uiautomation) ||
!GetChildElementByName(&elem, elem, L"toolStrip1", uiautomation) ||
!GetChildElementByName(&elem, elem, L"Print", uiautomation)
)
{
desktop->Release();
uiautomation->Release();
CoUninitialize();
return 1;
}
desktop->Release();
// The invoke control pattern contains the Invoke method that can be used to click the button
IUIAutomationInvokePattern * invokepattern;
if ( elem->GetCurrentPattern(UIA_InvokePatternId,
reinterpret_cast<IUnknown * *>(&invokepattern)) != S_OK )
{
std::cout << "GetCurrentPattern error.\n";
elem->Release();
uiautomation->Release();
CoUninitialize();
return 1;
}
if ( invokepattern == nullptr )
{
// Possibly element is not even a button, as it should have the invoke control pattern.
std::cout << "Invoke pattern not present.\n";
elem->Release();
uiautomation->Release();
CoUninitialize();
return 1;
}
// Click the button
if ( invokepattern->Invoke() != S_OK )
{
std::cout << "Button click failed.\n";
invokepattern->Release();
elem->Release();
uiautomation->Release();
CoUninitialize();
return 1;
}
elem->Release();
invokepattern->Release();
uiautomation->Release();
CoUninitialize();
std::cout << "Done.\n";
return 0;
}
bool GetChildElementByName(IUIAutomationElement * * Child,
IUIAutomationElement * Parent,
const wchar_t * Name, IUIAutomation * UIAut)
{
// Create a condition that matches elements with name *Name
IUIAutomationCondition * cond;
// Parameter for the condition is a string-typed VARIANT containing the name.
VARIANT name;
VariantInit(&name);
name.vt = VT_BSTR;
name.bstrVal = SysAllocString(Name);
if ( name.bstrVal == nullptr )
{
std::cout << "SysAllocString error.\n";
return false;
}
if ( UIAut->CreatePropertyCondition(UIA_NamePropertyId, name, &cond) != S_OK )
{
std::cout << "CreatePropertyCondition error.\n";
VariantClear(&name);
return false;
}
VariantClear(&name);
// Find the first child element satisfying the condition.
if ( Parent->FindFirst(TreeScope_Children, cond, Child) != S_OK )
{
std::cout << "FindFirst error.\n";
cond->Release();
return false;
}
cond->Release();
if ( *Child == nullptr )
{
std::cout << "Child element \"";
std::wcout << Name;
std::cout << "\" not found.\n";
return false;
}
// Child element found
return true;
}

Fixing assignment of an object's pointer members via smart pointers

I am learning more about smart pointers in C++14.
Consider the following MWC:
#include <iostream>
#include <string>
#include <memory>
class House {
public:
House &operator=(const House &house) = default;
House(const House &house) = default;
House(): id_habitants_(nullptr), num_habitants_() {}
explicit House(size_t num_habitants) {
if (num_habitants > 0) {
num_habitants_ = num_habitants;
id_habitants_ = new int[num_habitants_];
if (id_habitants_ != nullptr) {
for (size_t id = 0; id < num_habitants_; ++id) {
id_habitants_[id] = 1;
}
}
}
}
void Print() {
if (id_habitants_ != nullptr) {
for (size_t id = 0; id < num_habitants_; ++id) {
std::cout << id_habitants_[id] << ' ';
}
std::cout << std::endl;
} else {
std::cout << "<empty>" << std::endl;
}
}
~House() {
if (id_habitants_ != nullptr) {
delete [] id_habitants_;
}
num_habitants_ = 0;
}
private:
int *id_habitants_;
size_t num_habitants_;
};
int main() {
std::cout << "Testing unique_ptr.\n" << std::endl;
std::cout << "Using a dumb House class..." << std::endl;
std::cout << "Creating House h1 with 3 habitants..." << std::endl;
House h1(3);
std::cout << "IDs of h1's 3 habitants:" << std::endl;
h1.Print();
std::cout << "Creating House h2 with 0 habitants..." << std::endl;
House h2;
std::cout << "IDs of h2's 0 habitants:" << std::endl;
h2.Print();
std::cout << "Default-assigning h1 to h2..." << std::endl;
h2 = h1;
std::cout << "IDs of h2's new 3 habitants:" << std::endl;
h2.Print();
std::cout << "Destroying h1..." << std::endl;
h1.~House();
std::cout << "IDs of h2's new 3 habitants:" << std::endl;
h2.Print();
}
Without modifying the default copy constructor and the default assignment operator for the class House, how can I ensure correct pointer behavior during assignment via smart pointers?
On a first try it seems like using std::unique_ptr would be the way to go. I could create a new class:
class SmartHouse {
public:
SmartHouse &operator=(const SmartHouse &shouse) = default;
SmartHouse(const SmartHouse &shouse) = default;
SmartHouse(): id_habitants_(nullptr), num_habitants_() {}
explicit SmartHouse(size_t num_habitants) {
if (num_habitants > 0) {
num_habitants_ = num_habitants;
id_habitants_ = std::unique_ptr<int[]>(new int[num_habitants_]);
if (id_habitants_) {
for (size_t id = 0; id < num_habitants_; ++id) {
id_habitants_[id] = 1;
}
}
}
}
void Print() {
if (id_habitants_) {
for (size_t id = 0; id < num_habitants_; ++id) {
std::cout << id_habitants_[id] << ' ';
}
std::cout << std::endl;
} else {
std::cout << "<empty>" << std::endl;
}
}
~SmartHouse() {
num_habitants_ = 0;
}
private:
std::unique_ptr<int[]> id_habitants_;
size_t num_habitants_;
};
According to this, I can't really copy one unique pointer to another. Makes sense, right? It sort of defeats the purpose of it being unique. I.e. this would not compile:
SmartHouse sh1(3);
SmartHouse sh2;
sh2 = sh1;
But I could specify a move assignment operator and have the unique_ptr<int[]> member be moved upon assignment thus transferring ownership of the pointed data to the left object upon assignment:
class SmartHouse {
SmartHouse &operator=(SmartHouse &&SmartHouse) = default;
}
...
SmartHouse sh1(3);
SmartHouse sh2;
sh2 = std::move(sh1);
sh1.~SmartHouse();
sh2.Print();
Core question: Does this make sense at all? Are there better ways to enhance assignment of pointer member variables?
Full MWE.

Initializing a number and a char to a 2D array

I have to implement a deck of cards with a number and a letter. This is what I have done so far:
string deck [6][6] =
{
{1A, 1B, 1C, 1D},
{2A, 2B, 2C, 2D},
{3A, 3B, 3C, 3D},
{4A, 4B, 4C, 4D},
{ , , , };
};
int main ()
{
cout << deck[0][0] << endl;
}
I get an error:
invalid suffix 'A' on integer constant
You are getting this error because you need to wrap your strings in double quotations. If you want to use a static initialization/declaration, it should look something like this:
std::string deck[4][4] = {
{ "1A", "1B", "1C", "1D"},
{ "2A", "2B", "2C", "2D"},
{ "3A", "3B", "3C", "3D"},
{ "4A", "4B", "4C", "4D"}
};
You can display the entire contents of the deck by using two nested for loops:
for (int r=0; r < 4; ++r) {
for (int c=0; c < 4; ++c) {
if (c > 0) {
cout << " ";
}
cout << deck[r][c];
}
cout << "\n";
}

Resources