让我的库的用户使用原始值和 class 名称调用函数

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

我有一个不典型的要求。我正在编写一个设置库函数,它应该只用常量值和 class 名称调用。我做了这样的事情:

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
}

当我尝试使用我的功能时:

struct MyLayer {};


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

编译报错call of overloaded ‘setup_layers<LAYER_NUM, MyLayer>()’ is ambiguous

我不确定如何以其他方式完成我的要求:(。如果我可以通过普通参数将 class 名称作为参数传递给我的函数,那会很好,但 C++ 没有这样的功能...

编辑 好的,看来我的“解决方案”无处可去,根本行不通。 因为我不想删除有答案的问题,所以也许我应该换个方式问我的问题:

我希望我的图书馆的用户设置一个带有索引的层列表(其中这些索引中的数字不必有连续的数字)。我之所以想使用模板来做,是因为模板只能允许常量值作为参数。简单来说:我想禁止我的用户使用变量作为索引的参数。

有两个错误。

  1. setup_layers<Args...>(); 不会将任何整数模板参数传递给 setup_layers。没有 setup_layers 的定义在第一个位置没有 unsigned 值模板参数,因此此调用不匹配任何内容。尝试例如setup_layers<index+1, Args...>()>; 相反。

  2. 当只传递一个类型参数时,这两个重载是不明确的。

     template <unsigned index, class layerClass, typename...Args> ...
     template <unsigned index, class layerClass /*, nothing   */> ...
    

    一个空的 typename ... Args 参数包是合法的,没有理由偏爱一个空的参数包,反之亦然。尝试从第二个重载中删除 class layerClass (让它什么也不做)。 template <unsigned index> void setup_layers() {} 应该可以。

你可以这样做:

#include <iostream>
#include <typeinfo>

template <int index, class layerClass>
void setup_layers(int layer) {
    //add layer
    std::cout << "Adding layer " << layer << ": " << typeid(layerClass).name() << std::endl;
}

template <class layerClass, typename...Args>
void setup_layers(int layer) {
    //add layer
    //recursively call yourself
    if constexpr (sizeof...(Args) > 0) {
        setup_layers<0, layerClass>(++layer);
        setup_layers<Args...>(layer);
    } else {
        setup_layers<0, layerClass>(layer);
    }
}

struct MyLayer {};
struct OtherLayer {};

int main() {
    setup_layers<MyLayer, OtherLayer, MyLayer, OtherLayer>(0);
    std::cout << "End" << std::endl;
}

输出:

Adding layer 1: 7MyLayer
Adding layer 2: 10OtherLayer
Adding layer 3: 7MyLayer
Adding layer 3: 10OtherLayer
End

这里有一个解决歧义的选项:您可以重命名执行实际设置实现的函数。我将其命名为 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

如果每次使用层 class 时 index 都应该相同,您可以将层 [=27] 的 index 设为 属性 =]es.

示例:

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