dimanche 17 juillet 2022

C++: rvalues and rvalues reference

I am trying to experiment in C++ the concepts of rvalues and rvalues references. The following code illustrates my approach. I have written 2 foo functions, the first accepting a constant lvalue reference and the second an rvalue reference.

In the main, I call foo with an integer rvalue 2. Since rvalues can bind to constant lvalue references, why is the compiler choosing the second foo function? How does it know which function to use since both accept rvalues ..?

Thanks

void foo(const int& arg){
    std::cout << "foo(const int& arg) called!" << std::endl;
}

void foo(int&& arg){
    std::cout << "foo(int&& arg) called!" << std::endl; 
}

int main(){
   foo(2); // calls the function foo(int && arg), why? 
}

samedi 16 juillet 2022

Why does the compiler issue a template recursion error?

I'm currently trying to deduce a std::tuple type from several std::vectors that are passed as parameters. My code works fine using gcc, but the compilation fails with Visual Studio Professional 2019 with the message "fatal error C1202: recursive type or function dependency context too complex".

It has been mentioned for my previous post (C++ "fatal error C1202: recursive type or function dependency context too complex" in visual studio, but gcc compiles) that the problem is caused by template recursion as explained in C++ template compilation error - recursive type or function dependency. However, I don't see where the recursion occurs.

So my questions are:

Why is there an (infinite) recursion? How can it be resolved?

Here is the code (I'm bound to C++11):

#include <tuple>
#include <vector>

template <typename TT,typename Add>
auto addTupBase(TT t,std::vector<Add> a) ->decltype (std::tuple_cat(t,std::make_tuple(a[0])))
{
  return std::tuple_cat(t,std::make_tuple(a[0])) ;
}

template <typename TT,typename Add,typename... Args>
auto addTupBase(TT t,std::vector<Add> a,Args... args)-> decltype(addTupBase(addTupBase(t,a),args...))
{
  return addTupBase(addTupBase(t,a),args...);
}


template <typename T,typename... Args>
auto addTup(std::vector<T> in,Args... args) ->decltype(addTupBase(std::make_tuple(in[0]),args...))
{
  return addTupBase(std::make_tuple(in[0]),args...);
}

int main()
{
  using TupleType = decltype(addTup(std::vector<char>{2},std::vector<int>{5},std::vector<double>{32423}));
  TupleType t;
  std::get<2>(t) = 342.2;
  return 0;
}

Can unique mutex cause delay?

I wonder if the mutex of function "setEvent" can cause a delay in the following situations.


void CTest::threadFucn_run()
{
    while(true)
    {
        ... // tcp connect if client disconnected .. etc. (if connected, skip

        bool prev_event = m_bEvent;

        std::unique_lock<std::mutex> lock(m_mutex_event);        // "A"
        m_cv_event.wait_for(lock, std::chrono::seconds(10),
                [&] { return (m_bEvent != prev_event); }

        // proc (send message m_bEvent state or alive signal to server)
        ...
    }
}

void CTest::setEvent(bool _on)    // called from other class
{
    std::unique_lock<std::mutex> lock(m_mutex_event);        // "B"
    m_bEvent = _on;

    m_cv_event.notify_one();
}

The "m_" keyword is all member variables.

In normal cases, it is expected that "B" will lock, send an event message after m_bEvent changes, or send an alive status over period of 10 seconds.

However, in the worst case, if "A" is locked, can the "setEvent" function wait for up to less than 10 seconds? (Because of "B")

Even if the send event message is sent a little late, the setEvent should be returned as soon as possible.

I am currently checking the m_bEvent status by repeating the while statement(Sleep 10ms), but considering the CPU usage, I am considering introducing condition variable.

Significance of writing ios::sync_with_stdio(false); cin.tie(nullptr); [duplicate]

Why do we write "ios::sync_with_stdio(false); cin.tie(nullptr);" this statement in our C++ code ??

multiple definition, but it is the same definition [closed]

I have a problem that I can't solve, I'm making a little game for the university. In view of the review with the professor, I thought about refactoring the program. The problem is that I currently have a TurnSystem class that manages the turns and movement of the pieces. To make it work I use a file taken from the internet (https://www.redblobgames.com/pathfinding/a-star/implementation.html) reworked and adapted for my program. I have split this file into two Map.cpp and AStar.cpp. In the program right now, every time I need the map I have to recreate it (instead of modifying it), which greatly increases the computation cost.

The problem is that as long as the code is TurnSystem.cpp

includes "TurnSystem.h"
includes "AStar.cpp"
void TurnSystem::method{
   SquareGrid grid = MakeDiagram();
   //code
}

the code works. But if I change it like TurnSystem.h

includes "Librery.h"
includes "AStar.cpp"
class TurnSystem{
private:
   SquareGrid grid;
   //code
}

the code gives me error, saying that I am declaring different parts of Astar.cpp and Map.cpp several times es:

C: \ Program Files \ JetBrains \ CLion 2021.3.3 \ bin \ mingw \ bin / ld.exe: CMakeFiles / Reisende.dir / Game.cpp.obj: in function `__gnu_cxx :: new_allocator <std :: __ detail :: _ Hash_node_base *> :: new_allocator () ':
C: /Users/franc/Desktop/Reisende/Map.cpp: 74: multiple definition of `operator == (GridLocation, GridLocation) '; CMakeFiles / Reisende.dir / main.cpp.obj: C: /Users/franc/Desktop/Reisende/Map.cpp: 74: first defined here

TurnSystem is in turn included in a Game class, which in turn is included in Main.

I don't know how to fix it. I also thought about making grid a global variable. But I know it's not good practice Ideas? Thanks in advance

vendredi 15 juillet 2022

Initializing std::ofstream object in header file v/s source file

I came across some weird compilation error related to std::ofstream. Let's say, I have one header file ofstream_test.hpp, and its corresponding source file ofstream_test.cpp.

ofstream_test.hpp:

#include <iostream>
#include <fstream>

class OfstreamTest {
public:
    OfstreamTest();

    std::ofstream m_strm_obj("output.txt");
};

ofstream_test.cpp:

#include "ofstream_test.hpp"

OfstreamTest::OfstreamTest() {
    std::cout << "ctor" << std::endl;
}

main.cpp:

#include "ofstream_test.hpp"

int main(int argc, char const *argv[]) {
    OfstreamTest obj;
    return 0;
}

The error:

$ g++ -std=c++17 main.cpp ofstream_test.cpp 
In file included from main.cpp:1:0:
ofstream_test.hpp:8:30: error: expected identifier before string constant
     std::ofstream m_strm_obj("output.txt");
                              ^~~~~~~~~~~~
ofstream_test.hpp:8:30: error: expected ‘,’ or ‘...’ before string constant
In file included from ofstream_test.cpp:1:0:
ofstream_test.hpp:8:30: error: expected identifier before string constant
     std::ofstream m_strm_obj("output.txt");
                              ^~~~~~~~~~~~
ofstream_test.hpp:8:30: error: expected ‘,’ or ‘...’ before string constant

If I try to use the open method, I also get the compilation error (a bit different though):

ofstream_test.hpp:

class OfstreamTest {
public:
    OfstreamTest();
    std::ofstream m_strm_obj;
    m_strm_obj.open("output.txt");
};

ofstream_test.cpp:

OfstreamTest::OfstreamTest() {
    std::cout << "ctor" << std::endl;
}

The error:

$ g++ -std=c++17 main.cpp ofstream_test.cpp 
In file included from main.cpp:1:0:
ofstream_test.hpp:9:5: error: ‘m_strm_obj’ does not name a type
     m_strm_obj.open("output.txt");
     ^~~~~~~~~~
In file included from ofstream_test.cpp:1:0:
ofstream_test.hpp:9:5: error: ‘m_strm_obj’ does not name a type
     m_strm_obj.open("output.txt");
     ^~~~~~~~~~

However, for the following cases, I'm not getting any compilation error:

  • Case 1:

ofstream_test.hpp:

class OfstreamTest {
public:
    OfstreamTest();
};

ofstream_test.cpp:

OfstreamTest::OfstreamTest() {
    std::cout << "ctor" << std::endl;
    std::ofstream m_strm_obj("output.txt");  // initialized the object in source file, instead of header file
}
  • Case 2:

ofstream_test.hpp:

class OfstreamTest {
public:
    OfstreamTest();
    std::ofstream m_strm_obj{"output.txt"};  // just changed () to {}
};

ofstream_test.cpp:

OfstreamTest::OfstreamTest() {
    std::cout << "ctor" << std::endl;
}
  • Case 3:

ofstream_test.hpp:

class OfstreamTest {
public:
    OfstreamTest();
    std::ofstream m_strm_obj;  // declared the object but didn't initialize in the header file
};

ofstream_test.cpp:

OfstreamTest::OfstreamTest() {
    std::cout << "ctor" << std::endl;
    m_strm_obj.open("output.txt");
}

I don't understand why?

Would greatly appreciate an in-depth answer (or at least an answer with some reference links)!

Creating static map in C++ class [duplicate]

I am trying to create a std::map which maps an enum to a string (an enum of database types and their type name strings).

I have a enum class with each type, and a class with two public static function to convert from type to string and string to type.

If I make the definition of the map static I get the error a static data member with an in-class initializer must have non-volatile const integral type or be specified as 'inline' (I can't use inline because I am stuck with C++11)

Header file:

enum class DBDataType {
    Unset,
    Boolean,
    Character,
    Date,
    Double,
    Integer,
    Time,
    TimeStamp,
};

class DB_DT {
public:
    static std::string Type2Str(DBDataType type);
    static DBDataType Str2Type(std::string name);
private:
    static std::map<DBDataType, std::string> typeStringMap {
        {DBDataType::Boolean, "BOOLEAN"},
        {DBDataType::Character, "CHAR"},
        {DBDataType::Date, "DATE"},
        {DBDataType::Double, "DOUBLE"},
        {DBDataType::Integer, "INTEGER"},
        {DBDataType::Time, "TIME"},
        {DBDataType::TimeStamp, "TIMESTAMP"},
    };
    DB_DT();
};

CPP File:

std::string DB_DT::Type2Str(DBDataType type)
{
    auto pos = typeStringMap.find(type);
    if (pos == typeStringMap.end()) {
        return "";
    }
    else {
        return pos->second;
    }
}

DBDataType DB_DT::Str2Type(std::string name)
{
    for (auto it = typeStringMap.begin(); it != typeStringMap.end(); ++it) {
        if (it->second.compare(name)) {
            return it->first;
        }
    }
    return DBDataType::Unset;
}

So I changed the header declaration to static std::map<DBDataType, std::string> typeStringMap; create a function to fill the map if it is empty, which is checked from the converter functions:

std::string DB_DT::Type2Str(DBDataType type)
{
    if (typeStringMap.empty()) {
        createMap();
    }

    auto pos = typeStringMap.find(type);
    if (pos == typeStringMap.end()) {
        return "";
    }
    else {
        return pos->second;
    }
}

DBDataType DB_DT::Str2Type(std::string name)
{
    if (typeStringMap.empty()) {
        createMap();
    }

    for (auto it = typeStringMap.begin(); it != typeStringMap.end(); ++it) {
        if (it->second.compare(name)) {
            return it->first;
        }
    }
    return DBDataType::Unset;
}

void DB_DT::createMap()
{
    typeStringMap.emplace(DBDataType::Boolean, "BOOLEAN");
    typeStringMap.emplace(DBDataType::Character, "CHAR");
    typeStringMap.emplace(DBDataType::Date, "DATE");
    typeStringMap.emplace(DBDataType::Double, "DOUBLE");
    typeStringMap.emplace(DBDataType::Integer, "INTEGER");
    typeStringMap.emplace(DBDataType::Time, "TIME");
    typeStringMap.emplace(DBDataType::TimeStamp, "TIMESTAMP");
}

Which gives me the helpful error LNK2001: unresolved external symbol "private: static class std::map<DBDataType, std::string>

I don't understand this linking error, what exactly is wrong with this implementation? Would I be better off moving the definition of the map outside of the class?