在编译时用C++检测函数

Com*_* 10 6 c++ macros static templates

有没有办法,大概是使用模板,宏或两者的组合,我可以通常将一个函数应用于不同类的对象,但如果它们没有特定的功能,它们会以不同的方式响应吗?

我特别想要应用一个函数,如果对象具有该函数,将输出对象的大小(即集合中的对象数),但如果对象没有,则将输出一个简单的替换(例如"N/A") "T.即

NO_OF_ELEMENTS( mySTLMap ) -----> [ calls mySTLMap.size() to give ] ------>  10
NO_OF_ELEMENTS( myNoSizeObj ) --> [ applies compile time logic to give ] -> "N/A"
Run Code Online (Sandbox Code Playgroud)

我希望这可能类似于静态断言,尽管我显然想要编译不同的代码路径而不是在构建阶段失败.

Gri*_*zly 12

根据我的理解,您希望进行通用测试,以查看某个类是否具有某个成员函数.这可以使用SFINAE在C++中完成.在C++ 11中,它非常简单,因为您可以使用decltype:

template <typename T>
struct has_size {
private:
    template <typename U>
    static decltype(std::declval<U>().size(), void(), std::true_type()) test(int);
    template <typename>
    static std::false_type test(...);
public:
    typedef decltype(test<T>(0)) type;
    enum { value = type::value };
};
Run Code Online (Sandbox Code Playgroud)

如果你使用C++ 03,由于缺少它会更难decltype,所以你必须滥用sizeof:

template <typename T>
struct has_size {
private:
    struct yes { int x; };
    struct no {yes x[4]; };
    template <typename U>
    static typename boost::enable_if_c<sizeof(static_cast<U*>(0)->size(), void(), int()) == sizeof(int), yes>::type test(int);
    template <typename>
    static no test(...);
public:
    enum { value = sizeof(test<T>(0)) == sizeof(yes) };
};
Run Code Online (Sandbox Code Playgroud)

当然这会使用Boost.Enable_If,这可能是一个不需要的(和不必要的)依赖.然而写enable_if自己很简单:

template<bool Cond, typename T> enable_if;
template<typename T> enable_if<true, T> { typedef T type; };
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,方法签名test<U>(int)只有可见,如果Usize方法,因为否则评估decltypesizeof(取决于您使用的版本)将失败,这将从考虑中删除该方法(由于SFINAE.冗长的表达式std::declval<U>().size(), void(), std::true_type()是一个C++逗号操作符,其将返回从逗号分隔的列表的最后一个表达式,所以这可以确保类型被称为的滥用std::true_type为C++ 11变体(和sizeof求值int的C++ 03变体),该void()中中间只是为了确保逗号运算符没有奇怪的重载干扰评估.

当然,如果T有一个size可以不带参数调用的方法,这将返回true ,但不保证返回值.我假设您可能只想检测那些不返回void的方法.只需稍微修改一下test(int)方法即可轻松完成:

// C++11
template <typename U>
static typename std::enable_if<!is_void<decltype(std::declval<U>().size())>::value, std::true_type>::type test(int);
//C++03
template <typename U>
static typename std::enable_if<boost::enable_if_c<sizeof(static_cast<U*>(0)->size()) != sizeof(void()), yes>::type test(int);
Run Code Online (Sandbox Code Playgroud)


Mat*_* M. 9

关于constexpr某些人以前的能力的讨论.我觉得是时候使用了它:)

使用constexpr和设计特征很容易decltype:

template <typename T>
constexpr decltype(std::declval<T>().size(), true) has_size(int) { return true; }

template <typename T>
constexpr bool has_size(...) { return false; }
Run Code Online (Sandbox Code Playgroud)

事实上,这种特质很容易失去其大部分价值:

#include <iostream>
#include <vector>

template <typename T>
auto print_size(T const& t) -> decltype(t.size(), void()) {
  std::cout << t.size() << "\n";
}

void print_size(...) { std::cout << "N/A\n"; }

int main() {
  print_size(std::vector<int>{1, 2, 3});
  print_size(1);
}
Run Code Online (Sandbox Code Playgroud)

在行动:

3
N/A
Run Code Online (Sandbox Code Playgroud)