c++named-constructor

Technique to force constructor calls to be easily searchable


I would like to write a constructor in a way that finding all usages is easy to do with global file search

An attempt at doing this is below but it is inadequate:

#include <iostream>

struct Example {
    enum class ECtor { eCtor };
    explicit Example(ECtor) { std::cout << "Ctor" << std::endl; }
};

int main() {
    // Intended requirement: constructor calls can be searched for by searching
    // for "ECtor"
    Example good(Example::ECtor::eCtor);

    // Problem: This compiles which ruins the intention
    Example bad({});

    return 0;
}

Unfortunately {} can be used as an argument despite the constructor being explicit meaning searching for "ECtor" will not find the usage

The argument could be made that searching for Example could be done instead but in a large framework that can be very time consuming due to inheritance and containers

I am aware of the named constructor idiom but that also comes with issues. For example, it may be the case that a class can be instantiated with new in some places, with custom new calls in other places, on the heap in other places, etc. Each would require its own named method so I'd rather avoid that approach


Solution

  • A possible approach is to define a deleted constructor which receives an initializer list. In this way, {} is interpreted as an initializer list instead of an enum.

    #include <iostream>
    #include <initializer_list>
    
    struct Example {
        enum class ECtor { eCtor };
        explicit Example(ECtor) { std::cout << "Ctor" << std::endl; }
        explicit Example(std::initializer_list<double>) = delete;
    };
    
    int main() {
        // Intended requirement: constructor calls can be searched for by searching
        // for "ECtor"
        Example good(Example::ECtor::eCtor);
    
        // This don't compile anymore
        Example bad({});
    
        return 0;
    }