Reputation: 5894
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
Upvotes: 0
Views: 82
Reputation: 1103
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;
}
Upvotes: 1