samedi 27 juin 2020

C++ only forward construction if the object has not been created

Basically I've been looking into unordered_map and see that they delay construction of the value (if possible) with emplace.

I am trying to implement something similar and am able to forward an objects construction, but I also am forwarding already constructed objects.

I am looking for help on how I can check if an object is already created (in which case I would want to use std::move(obj) versus if just the pieces for construction have been passed in which case I want to use std::forward<Args>(args)...

This is the code I've been trying to use to figure this out but I have been unable to figure it out.

#include <vector>
#include <string>

#include <stdio.h>

template<typename T>
struct tester {
    std::vector<T> v;

    tester() : v(0) {}

    //we have a reference to existing object
    void
    add(const char * vname, const T & t) {
        fprintf(stderr, "Const lRef -> %s\n\n", vname);
        v.push_back(t);
    }

    //we have an actual copy
    void
    add(const char * vname, T && t) {
        fprintf(stderr, "Const rRef -> %s\n\n", vname);
        v.push_back(std::move(t));
    }

    //we have parameters necessary for construction
    template<typename... Args>
    void
    add(const char * vname, Args && ...args) {
        fprintf(stderr, "vArgs      -> %s\n\n", vname);
        v.push_back(std::forward<Args>(args)...);
    }
    
};


#define VAR_TO_STR(X) #X
#define ADD(X) add(VAR_TO_STR(X), (X))

int
main() {

    tester<std::string> str_tester;

    std::string constructed_str("Already Constructed String");
    const std::string const_constructed_str("Const Already Constructed String");
    
    str_tester.ADD("String That Can Be Constructed In Place");
    str_tester.ADD(constructed_str);
    str_tester.ADD(const_constructed_str);


    tester<int> int_tester;

    int constructed_int = 10;
    const int const_constructed_int = 50;

    int_tester.ADD(1);
    int_tester.ADD(constructed_int);
    int_tester.ADD(const_constructed_int);
}

The output is:

vArgs      -> "String That Can Be Constructed In Place"

vArgs      -> constructed_str

Const lRef -> const_constructed_str

Const rRef -> 1

vArgs      -> constructed_int

Const lRef -> const_constructed_int

I am basically looking for a way so that constructed_int and constructed_str can go to the "lRef" or "rRef" as reconstructing from copy constructor is pretty expensive.

Thank you!

Edit: To some degree I figured it out:

    //we have a reference to existing object
    void
    add(const char * vname, T & t) {
        fprintf(stderr, "lRef       -> %s\n\n", vname);
        v.emplace_back(t);
    }

will cause a non-const already constructed version of T to go here.

Aucun commentaire:

Enregistrer un commentaire