Search code examples
c++implicit-conversionfunction-parameter

How to avoid implicit conversions from integer 0 to pointer, as the element of a vector


There is a situation where I want to collect all the nodes names of a path to one key in JSON. Consider the condition: JSON array index "0", "1" are also allowed, but it is easy to forget the quotes, which would lead to a crash when doing dereference. So I want compiler to reject this kind of parameters. Example:

#include <vector>
#include <iostream>

int func(const std::vector<const char*>& pin) {
    return pin.size();
}

int main() {
    // {"aname", "3", "path", "0"} wanted but this still compile
    std::cout << func({"aname", "3", "path", 0}) << std::endl;
}

Refering to How do I avoid implicit conversions on non-constructing functions? I tried something as following:

#include <vector>
#include <iostream>

// I want to describe only char pointer parameter is allowed as element,
// parameter of any integer types should be rejected.
int func(const std::vector<const char*>& pin) {
    return pin.size();
}

int func(const std::vector<int>& pin) = delete;
// or
template<typename T>
int func(const std::vector<T>& pin) = delete;

int main() {
    std::cout << func({"aname", "3", "path", 0}) << std::endl;
}

But the compiler still can not understand me.
Any suggestion?

Please point out any misuse of terminologies and assumptions, thank you!


Solution

  • Something like this? It's very similar to the overload solution you suggested, but requires wrapping the vector type. Fails to build if you provide a literal 0 because the deleted constructor overload is chosen.

    #include <memory>
    #include <new>
    #include <vector>
    #include <iostream>
    using std::vector;
    
    template<typename T>
    struct no_zero {
            no_zero(T val) : val(val) {}
            no_zero(int val) = delete;
            operator T() { return val; }
            T val;
    };
    
    int func(const vector<no_zero<const char*> >& pin) {
        return pin.size();
    }
    
    int main() {
        // {"aname", "3", "path", "0"} wanted but this still compile
        std::cout << func({"aname", "3", "path", 0}) << std::endl;
    }