【问题标题】:Compile time detection of functions函数的编译时检测
【发布时间】:2015-01-04 22:23:51
【问题描述】:

我正在开发一个小的编译时助手,让我确定是否存在具有特定签名的函数(目前:没有命名空间或类成员函数)(例如,广泛传播的 __builtin_pop_count,但不能保证可在任何平台上使用)。

对于固定数量的参数,这很容易做到:

template <typename ReturnType, typename ArgumentType, typename = void>
struct Exists : std::false_type // Base case
{
};

template <typename T>
using void_t = void;

template <typename T>
using return_t = decltype(foo(std::declval<T>())); // here it is hidden: foo, although this symbol is never declared!

// specialization (compiler has to pick this one if no substitution failure in return_t
template <typename ReturnType, typename ArgumentType>
struct Exists<ReturnType, ArgumentType, void_t<return_t<ArgumentType>>>
  : std::is_same<return_t<ArgumentType>, ReturnType> // check the return type
{
};

static_assert(!Exists<void, int>::value, "");
static_assert(!Exists<void, void>::value, "");
static_assert(!Exists<void, char*>::value, "");
static_assert(!Exists<int, void>::value, "");
static_assert(!Exists<int, int>::value, "");
static_assert(!Exists<int, char*>::value, "");

这编译得很好。添加函数void foo(int) 否定第一个断言,但保持其余部分不变。

现在我想扩展这个助手来支持任意数量的参数类型。

然而,

template <typename ReturnType, typename... ArgumentTypes, typename = void>

不能工作,因为typename...必须在列表末尾,

template <typename ReturnType, typename = void, typename... ArgumentTypes>

另一方面,要求以下 ArgumentTypes 具有默认类型,这也是不可能的。

我该如何规避这个问题? std::tuple&lt;ArgumentTypes...&gt; 可以提供任何帮助吗?

【问题讨论】:

    标签: c++ c++14 template-meta-programming compile-time


    【解决方案1】:

    你猜对了。
    使用pack 模板,并“简化”一点:

    template <typename...> struct pack {}; // To be potentially introduced in C++1Z
    
    template <typename, typename, typename=void>
    struct Exists_impl : std::false_type {};
    
    template <typename R, typename... Args>
    struct Exists_impl<R, pack<Args...>,
      std::enable_if_t<std::is_same<decltype(foo(std::declval<Args>()...)), R>::value>>
        : std::true_type {};
    
    template <typename R, typename... Args>
    using Exists = Exists_impl<R, pack<Args...>>;
    

    Demo.
    请注意,此模板将永远无法通过 ADL 找到像 void(int) 这样的函数,因为在这种情况下关联的命名空间集是空的。这些函数必须在定义时声明。
    此外,根据用例,使用is_convertible 而不是is_same 来检查返回类型可能是可行的。

    【讨论】:

    • 如果他们只想要一个类型列表,什么时候应该使用pack 而不是常规元组?
    • @0x499602D2 tuple 是一个沉重的模板。除非真的有必要,否则永远不要在 TMP 中使用它。
    • 如果您使用is_convertible,您可能希望专门针对void 返回类型,除非您希望int foo(); 与签名void() 不兼容。或者不,如果您希望被阻止!
    猜你喜欢
    • 2012-02-13
    • 2019-09-28
    • 1970-01-01
    • 1970-01-01
    • 2011-04-05
    • 2013-09-29
    • 2012-04-09
    • 2017-05-01
    • 1970-01-01
    相关资源
    最近更新 更多