如何防止不实现方法的对象生成模板

Jon*_*Mee 3 c++ methods lambda templates metaprogramming

所以出于示例的目的,假设我有3个简单的structs,其中第二个不包含bar方法:

struct one {
    void foo(const int);
    void bar();
};

struct two {
    void foo(const int);
};

struct three {
    void foo(const int);
    void bar();
};
Run Code Online (Sandbox Code Playgroud)

然后我有一个struct将管理这些类型的对象:

struct owner {
    map<int, one> ones;
    map<int, two> twos;
    map<int, three> threes;

    template <typename T, typename Func>
    void callFunc(T& param, const Func& func) {
        func(param);
    }

    template <typename T>
    void findObject(int key, const T& func) {
        if(ones.count(key) != 0U) {
            callFunc(ones[key], func);
        } else if(twos.count(key) != 0U) {
            callFunc(twos[key], func);
        } else {
            callFunc(threes[key], func);
        }
    }

    void foo(const int key, const int param) { findObject(key, [&](auto& value) { value.foo(param); } ); }
    void bar(const int key) { findObject(key, [&](auto& value) { value.bar(); } ); }
};
Run Code Online (Sandbox Code Playgroud)

当我尝试编译这个时,我得到:

错误:struct two没有成员命名bar

有没有办法可以解决这个问题?

Live Example

T.C*_*.C. 11

首先,公用事业.一个是我们最喜欢的overload,展示了三个C++ 17特性,并且重载了operator()几个函数对象,全部分为两行.

template<class... Ts> struct overload : Ts... { using Ts::operator()...; };
template<class... Ts> overload(Ts...) -> overload<Ts...>;
Run Code Online (Sandbox Code Playgroud)

然后是accept-everything回退标记类型:

struct fallback_t { template<class T> fallback_t(T&&) {} };
Run Code Online (Sandbox Code Playgroud)

现在来电话本身.我们通过将value.bar()调用放入尾随返回类型来使原始泛型lambda SFINAE友好,然后使用具有未定义行为的回退重载来重载它(如果实际调用的话)(因为OP"省略[ted]任何显式的行为定义"):

void bar(const int key) { 
    findObject(key, overload {
          [&](auto& value) -> decltype(void(value.bar())) { value.bar(); },
          [](fallback_t){ fire_missiles_and_impregnate_cat(); }
    } ); 
}
Run Code Online (Sandbox Code Playgroud)

  • 我用导弹很好,但猫! (4认同)
  • 我喜欢这个,但我确信OP会理解为什么这个有效. (2认同)