模板参数未满足所有要求

Templates arguments not fulfulling all requirements

本文关键字:未满足 参数      更新时间:2023-10-16

这是可能的:

struct A {
    //void f();  < not declared in struct A
};
template<typename T>
struct Wrapper {
    T t;
    void call_f() { t.f(); }
};
int main() {
    Wrapper<A> w;
}

只要不调用w.call_f(),这个编译就很好。由于A::f不存在,因此无法实例化w.call_f()

我遇到了这样一个包装器模板的情况,它与不同的T类型一起使用,这些类型并不总是实现接口的所有部分。(主要是为了避免代码重复(。

这不起作用:

struct A {
    //using i_type = int;   < not declared/defined
};
template<typename T>
struct Wrapper {
    using its_i_type = typename T::i_type;
       // compile error, even if `i_type` gets never used
};
int main() {
    Wrapper<A> w;
}

这也不行:

struct A {
    //using i_type = int;   < not declared/defined
};
template<typename T>
struct Wrapper {
    typename T::i_type call_f() { return 0; }
       // does not compile, even if `call_f()` is never instantiated
};
int main() {
    Wrapper<A> w;
}

有没有一种好的方法来处理这些情况,而不需要大量的代码重复(比如Wrapper的专业化等(?

您可以推迟its_i_type的类型推导。基本上,您创建了一个必须经过的简单包装器。


为了将其扩展到您需要的其他类型,(我想推荐类似type_traits的解决方案,但由于您不想要专业化(您可以定义您需要的所有类型:

template<typename T>
struct Wrapper {
private:
    template<typename U> struct i_typper { using type = typename U::i_type; };
    template<typename U> struct k_typper { using type = typename U::k_type; };
    template<typename U> struct p_typper { using type = typename U::p_type; };
public:
    using i_trait = i_typper<T>;
    using k_trait = k_typper<T>;
    using p_trait = p_typper<T>;
};

示例:

struct A { using i_type = int; };
struct B { using i_type = int;    using k_type = float; };
int main() {
    Wrapper<A> w;   //Works now.
    Wrapper<A>::i_trait::type  mk1;  //Works
    Wrapper<A>::k_trait::type  mk2;  //Fails, not defined
    Wrapper<B>::i_trait::type  mk3;  //Works
    Wrapper<B>::k_trait::type  mk4;  //Works
}

对于以下情况:

template<typename T>
struct Wrapper {
    typename T::i_type call_f() { return 0; }
       // does not compile, even if `call_f()` is never instantiated
};

这里有几个选项:

  1. 使该函数成为成员函数模板
  2. 使用某种形式的type_traits机制,该机制仍将涉及专业化
  3. 采用抽象基类WrapperBase中常见的Wrapper内容的方法

对于第一个选项,您必须对其进行一点修改,以进一步推迟扣除

template<typename T>
struct Wrapper {
private:
    template<typename U, typename> struct i_typper { using type = typename U::i_type; };
    template<typename U, typename> struct k_typper { using type = typename U::k_type; };
    template<typename U, typename> struct p_typper { using type = typename U::p_type; };
public:
    using i_trait = i_typper<T, void>;
    using k_trait = k_typper<T, void>;
    using p_trait = p_typper<T, void>;
    template<typename U = void>
    typename k_typper<T, U>::type call_f() { return 0; }
};

我将把第二个选项作为练习:(它可能最终会变成:

template<typename T>
struct wrapper_traits {
    ....
};
template<>
struct wrapper_traits<A>{
   using ....
};
template<typename T>
struct Wrapper {
   ....
public:
    using i_trait = wrapper_traits<T>;
    using k_trait = wrapper_traits<T>;
    using p_trait = wrapper_traits<T>;
};

贾罗德的答案更简单。但如果您没有访问std::experimental的权限,或者您的公司代码政策禁止您。。。

使用std::experimental::is_detected,您可以进行

template<typename T>
using i_type_t = typename T::i_type;
template<typename T>
struct Wrapper {
    using its_i_type = typename std::experimental::detected_t<i_type_t, T>;
       // would be T::i_type or std::experimental::nonesuch
};

或者为了更好地处理案件,比如:

template<typename T, bool = std::experimental::is_detected<i_type_t, T>::value>
struct WrapperWithIType {
    // Empty for false case.
};
template<typename T>
struct WrapperWithIType<T, true> {
    using its_i_type = i_type_t<T>;
    its_i_type call_f() { return 0; }
};

然后

template<typename T>
struct Wrapper : WrapperWithIType<T> {
    // Common stuff
};