lundi 22 janvier 2024

How to simplify these function template specializations?

I am working on some legacy code that has the following template defined in a header file:

template<typename T>
std::string convertToString(const T& t);

In the same header file, there are specializations for some user-defined types. In the .cpp file, there are specializations for the types int, unsigned short and unsigned long as follows:

template<>
std::string convertToString<unsigned short>(const unsigned short& s) {
    ... some implementation ...
}

template<>
std::string convertToString<int>(const int & s) {
    ... some implementation ...
}

template<>
std::string convertToString<unsigned long>(const unsigned long& value) {
    ... some implementation ...
}

The implementations don't make use of C++11's std::to_string function. I would like to simplify this code so that for all types that std::to_string supports, namely

int
long
long long
unsigned
unsigned long
unsigned long long
float
double
long double

the template specialization uses the simple implementation (e.g. for int):

template<>
std::string convertToString(const int& n) { return std::to_string(n); }

I could of course write down all template specializations for all the above mentioned types, but that doesn't seem like a nice way to do it. My current best solution to have these template specializations for all types that std::to_string takes is to add the following to my header file:

template<typename T>
std::string convertToString(const T& t);

template <typename T,
          typename = typename std::enable_if<std::is_arithmetic<T>::value>::type>
std::string convertToString(const T& t)
{
    return std::to_string(t);
}

I think this is close to a solution, but not yet as I get the following ambiguity error:

error: call of overloaded 'convertToString(long unsigned int&)' is ambiguous

referring me to the above two template functions as possible candidates. I don't quite understand why the first one is also a possible candidate if the second one exists...

How can I add template specializations for all the types that std::to_string supports, and also still allow for user-defined types T in the convertToString function template? Solution should be restricted to C++11 for now...

samedi 13 janvier 2024

C++: how to locate the exception?

I have the following test code.

#include <exception>
#include <iostream>

void terminate_handler() {
    auto const ep = std::current_exception();
    if(ep) {
        try {
            std::rethrow_exception(ep);
        } catch(const std::logic_error& le) {
            std::cerr << "terminating with std::logic_error: " << le.what()
                      << std::endl;
        }
    }
    std::abort();
}

int main(int argc, char* argv[]) {
    std::set_terminate(terminate_handler);
    std::string(0);
    return 0;
}

It is working fine, but I want to add filename and line number like below if possible.

terminating with std::logic_error: basic_string::_M_construct null not valid at main.cpp:26.

Segmentation fault on nullptr check when incrementing the ptr to iterate over an array

The following code, when compiled and run gives a segmentation fault. I was trying out the sample on page 12 of a Tour of C++ on a MacBook.

compilation command - clang++ -Wall -std=c++11 -o replacement.o replacement.cpp && ./replacement.o

Error message - 'zsh: segmentation fault ./replacement.o'

Full code -

#include <iostream>

int count_occurances(char* p, char x)
{
    int count = 0;
    // count number of times x occurs in p
    while (p != nullptr)
    {
        if (*p == x)
            ++count;
        ++p;
    }
    return count;
}

int main(int argc, const char * argv[]) {
    // insert code here...
    char num_array[4] = {'a', 'b', 'b', 'c'};
    std::cout << "Running count occurances array" << count_occurances(num_array, 'b') << "done\n" ;
    return 0;
}

Essentially tried to iterate over the array by incrementing the pointer but somehow messing up the nullptr check, as a result it's accessing memory it shouldn't.

dimanche 31 décembre 2023

How to compile an OpenGL project in CMake in Wayland desktop environment?

I'm trying to setup a project that uses OpenGL as library for graphic development; in particular, I want to use CMake for compiling the project to make it cross-platform. I'm running the project on Arch Linux distro with KDE as desktop environment.

This is my CMakeLists.txt:

cmake_minimum_required(VERSION 3.5.0)
project(run VERSION 0.1.0 LANGUAGES C CXX)

include(CTest)
enable_testing()

add_executable(run main.cpp)
target_link_libraries(
    run PUBLIC
    /usr/lib/libglut.so.3
    /usr/lib/libOpenGL.so.0
    /usr/lib/libglfw.so.3.3
    /usr/lib/libGLEW.so.2.2
    /usr/lib/libdecor/plugins-1/libdecor-gtk.so
)
################################################
set(INCLUDE_ROOT_FOLDER "/usr/include")

target_include_directories(
    run PUBLIC
    ${INCLUDE_ROOT_FOLDER}/GL
    ${INCLUDE_ROOT_FOLDER}/GLFW
    ${INCLUDE_ROOT_FOLDER}/libdecor-0
    ${INCLUDE_ROOT_FOLDER}
)
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)

and this is main.cpp:

#include <iostream>
#include <glew.h>
#include <glut.h>
#include <GLFW/glfw3.h>

int main()
{
    glutInitDisplayMode(GLUT_RGB);
    glfwInit();
    return 0;
}

When compiling, everything is fine. However, this is the error I get at run-time: xkbcommon: ERROR: couldn't find a Compose file for locale "it_IT..UTF-8" (mapped to "it_IT..UTF-8") libdecor-gtk-WARNING: Failed to initialize GTK Failed to load plugin 'libdecor-gtk.so': failed to init

mercredi 27 décembre 2023

Replace boost::timed_wait() with std in c++17

I have a condition variable std::condition_variable my_cond;

I want to be able to replace boost::timed_wait() with an std equivalent one.

If the previously mentioned condition variable was a boost one, then I would use the boost version of timed_wait() like this: cond_.timed_wait(lock,timeout);

where lock is std::scoped_lock lock(mutex_); and timeout is a time that is performed with boost::chrono.

boost:chrono, boost locks and boost mutexes have been replaced with their std analogues. I have yet to find an alternative to timed_wait().

I try to find a function belonging to std, where it receives the lock as the first parameter and an std::chrono type time as a second parameter. Looking at the documentation of the condition_variable::wait here: https://en.cppreference.com/w/cpp/thread/condition_variable/wait

I don't see an overloaded wait function where the second argument is a time type.

Is this conversion from boost::timed_wait() to std::wait() possible?

mardi 19 décembre 2023

Overloaded Templates and non-template functions

I encountered a problem about "Overloaded Templates and non-template functions".

#include <string>
#include <sstream>
#include <iostream>

using namespace std;

// print any type we don't otherwise handle
template <typename T>
string debug_rep(const T &t) {
    ostringstream ret;
    ret << t; // uses T's output operator to print a representation of t
    return ret.str(); // return a copy of the string to which ret is bound
}

// print pointers as their pointer value, followed by the object to which the pointer pointsv
template <typename T>
string debug_rep(T *p) {
    ostringstream ret;
    ret << "pointer: " << p;  // print the pointer's own value
    if (p) {
        ret << " " << debug_rep(*p);  // print the value to which p points
    } else {
        ret << " null pointer";  // or indicate that the p is null
    }
    return ret.str();  // return a copy of the string to which ret is bound
}

string debug_rep(char * p) {
    return debug_rep((string)p);
}

string debug_rep(const char * p) {
    return debug_rep((string)p);
}

int main() {
    string debug_rep(const string& s);
    const char * cp = "hello";
    cout << debug_rep(cp) << endl;

    return 0;
}

string debug_rep(const string& s) {
    return '"' + s + '"';
}

In the book "C++ Primer", they say the cout << debug_rep(cp) << endl; in main function will call debug_rep(const char * p). However, through my test, it actually calls debug_rep(const string& s). So, I wonder why this happened.

samedi 16 décembre 2023

How virtual keyword in virtual inheritance causing a error [duplicate]

I have two set of code :

First case :

#include<iostream>
using namespace std;
class A {
public:
    virtual void display() { cout << "A display \n"; }
};

class B : virtual public A {
public:
    void display() { cout << "B display \n"; }
};

class C : virtual public A {
public:
    void display() { cout << "C display \n"; }
};

class D : public C, public B {
public:
    D() {};
};

int main() {
    D d;
    d.B::display(); // ERROR
}

Error :

Error (active)  E0318   override of virtual function "A::display" is ambiguous
Error   C2250   'D': ambiguous inheritance of 'void A::display(void)'

Second case :

#include<iostream>
using namespace std;
class A {
public:
    void display() { cout << "A display \n"; }
};

class B : virtual public A {
public:
    void display() { cout << "B display \n"; }
};

class C : virtual public A {
public:
    void display() { cout << "C display \n"; }
};

class D : public C, public B {
public:
    D() {};
};

int main() {
    D d;
    d.B::display(); // Output B display
}

The only difference in above two cases is in first one I am making "virtual void display()" in class A, why it is failing in first case while passing in second case?