Search code examples
c++templatesvariadic-templates

Make users of my library to call function with primitive values and class names as well


I have got an untypical requirement. I'm writing a setup library function, which should be called with only constant values and class names. I made something like this:

template <unsigned index, class layerClass, typename...Args>
void setup_layers() {
     //add layer
     //recursively call yourself
     setup_layers<Args...>();
}

template <unsigned index, class layerClass>
void setup_layers() {
     //add layer
}

When I try use my function:

struct MyLayer {};


int main (int argc, char **argv)
{
    constexpr unsigned LAYER_NUM = 0;
    setup_layers<LAYER_NUM, MyLayer>();
    return 0;
}

the compiler reports the error call of overloaded ‘setup_layers<LAYER_NUM, MyLayer>()’ is ambiguous

I'm not sure how can I accomplish my requirement in the other way :(. If I could pass class names as parameters to my function via normal arguments it would be fine, but C++ has no such feature...

EDIT OK, it seems my "solution" goes nowhere and simply doesn't work. Because I don't want to delete a question with answers, then maybe I should ask my question differently:

I want users of my library to set a list of layers with indexes (where numbers in those indexes doesn't have to have consecutive numbers). The reason why I wanted to do it using templates is because templates can allow only constant values as parameters. To put it simply: I want to forbid my users from using variables as parameters for indexes.


Solution

  • Here's one option to resolve the ambiguity: You could rename the function doing the actual setup implementation. I've called it setup_impl:

    template <unsigned index, class layerClass>
    void setup_impl() {
        //add layer
        std::cout << index << '\n';
    }
    
    template <unsigned index, class layerClass, class... Args>
    void setup_layers() {
        setup_impl<index, layerClass>();
        if constexpr (sizeof...(Args) > 0) {
            setup_layers<index + 1, Args...>();
        }
    }
    

    Demo

    If index is supposed to be the same every time a Layer class is used, you could make the index a property of the Layer classes.

    Example:

    template <class layerClass>
    void setup_impl() {
        std::cout << layerClass::index << '\n';
    }
    
    template <class... Args>
    void setup_layers() {
        (setup_impl<Args>(), ...); // fold expression
    }
    
    struct MyLayer1 { static constexpr unsigned index = 11; };
    struct MyLayer2 { static constexpr unsigned index = 22; };
    struct MyLayer3 { static constexpr unsigned index = 33; };
    

    Demo