我开始慢慢填补我关于C ++模板的知识空白,在阅读了很多关于如何在编译器实际进入模板化代码之前处理错误之后,我想出了以下结构来检查是否存在object提供了我需要的接口。
所需的界面在Model类中可见。
#include <iostream>
#include <type_traits>
template <typename T>
struct is_model {
private:
template <typename B, typename A> struct size_t_allowed;
template <typename B> struct size_t_allowed<B, size_t>{};
template <typename B, typename A> struct double_allowed;
template <typename B> struct double_allowed<B, double>{};
template <typename Z> static auto test(const Z* z) -> decltype(
size_t_allowed<size_t,decltype(z->getS())>(),
size_t_allowed<size_t,decltype(z->getA())>(),
double_allowed<double,decltype(z->getTransitionProbability(0,0,0))>(),
double_allowed<double,decltype(z->getExpectedReward(0,0,0))>(),
std::true_type{} );
template <typename> static auto test(...) -> std::false_type;
public:
enum { value = std::is_same<decltype(test<T>(0)), std::true_type>::value };
};
struct Model {
size_t getS() const { return 0;}
size_t getA() const { return 0;}
double getTransitionProbability(size_t, size_t, size_t) const {return 0.0;}
double getExpectedReward(size_t, size_t, size_t) const {return 0.0;}
};
template <typename M>
void algorithm(M, typename std::enable_if<is_model<M>::value>::type * = nullptr) {
std::cout << "Algorithm has been performed.\n";
}
int main() {
std::cout << is_model<int>::value << "\n";
std::cout << (is_model<Model>::value ? "Yes" : "No" ) << "\n";
Model m;
algorithm(m);
return 0;
}
我的问题如下:
is_model<Model>::value
返回false,并且无法编译algorithm(m)
。哪个是对的? *_allowed
使用单个模板参数,否则编译器会在类范围内抱怨一个专门的结构。编辑:
感谢Jarod's answer我改进了我的解决方案。因为我喜欢它的清洁度,所以我仍然将所有内容保持在一个单独的类中。另外我发现了clang的问题:由于某些原因,在特定情况下,它无法正确解析std::true_type{}
,std::declval<std::true_type>()
也无法正常解析。用std::true_type()
代替它。仍然没有任何线索,我甚至试图重新安装整个事情。
template <typename T>
struct is_model {
private:
template<typename U, U> struct helper{};
template <typename Z> static auto test(Z* z) -> decltype(
helper<size_t (Z::*)() const, &Z::getS>(),
helper<size_t (Z::*)() const, &Z::getA>(),
helper<double (Z::*)(size_t,size_t,size_t) const, &Z::getTransitionProbability>(),
helper<double (Z::*)(size_t,size_t,size_t) const, &Z::getExpectedReward>(),
std::true_type());
template <typename> static auto test(...) -> std::false_type;
public:
enum { value = std::is_same<decltype(test<T>((T*)nullptr)),std::true_type>::value };
};
答案 0 :(得分:2)
以下可能有所帮助,它会检查完整的签名:
#include <cstdint>
#include <type_traits>
#define DEFINE_HAS_SIGNATURE(traitsName, funcName, signature) \
template <typename U> \
class traitsName \
{ \
private: \
template<typename T, T> struct helper; \
template<typename T> \
static std::uint8_t check(helper<signature, &funcName>*); \
template<typename T> static std::uint16_t check(...); \
public: \
static \
constexpr bool value = sizeof(check<U>(0)) == sizeof(std::uint8_t); \
}
DEFINE_HAS_SIGNATURE(has_getS, T::getS, size_t (T::*)() const);
DEFINE_HAS_SIGNATURE(has_getA, T::getA, size_t (T::*)() const);
DEFINE_HAS_SIGNATURE(has_getTransitionProbability, T::getTransitionProbability, double (T::*)(size_t, size_t, size_t) const);
DEFINE_HAS_SIGNATURE(has_getExpectedReward, T::getExpectedReward, double (T::*)(size_t, size_t, size_t) const);
template <typename T>
struct is_model :
std::conditional<has_getS<T>::value
&& has_getA<T>::value
&& has_getTransitionProbability<T>::value
&& has_getExpectedReward<T>::value,
std::true_type, std::false_type>::type
{};
测试它:
struct Model {
size_t getS() const { return 0;}
size_t getA() const { return 0;}
double getTransitionProbability(size_t, size_t, size_t) const {return 0.0;}
double getExpectedReward(size_t, size_t, size_t) const {return 0.0;}
};
static_assert(is_model<Model>::value, "it should respect contract");
static_assert(!is_model<int>::value, "it shouldn't respect contract");