了解有关 type_traits 的更多信息

Understanding more about type_traits

提问人:Joseph Larson 提问时间:12/14/2021 最后编辑:François AndrieuxJoseph Larson 更新时间:12/15/2021 访问量:407

问:

设置

我昨天问了一个关于模板方法重载和使用类型特征解决问题的问题。我收到了一些很好的答案,他们引导我找到了解决方案。这个解决方案使我开始了更多的阅读。

我登上了Fluent CPP的一个页面-- https://www.fluentcpp.com/2018/05/18/make-sfinae-pretty-2-hidden-beauty-sfinae/ 很有意思,然后我听了Boccara先生引用的Stephen Dewhurst的演讲。这一切都令人着迷。

我现在正试图了解更多。在昨天的答案中,我得到了这个解决方案:

     template< class Function, class... Args,
              std::enable_if_t<std::is_invocable_v<Function, Args...>, std::nullptr_t> = nullptr>
     explicit MyClass( const std::string & theName, Function&& f, Args&&... args )
        : name(theName)
     {
        runner(f, args...);
     }

备选答案

在阅读了 CPP Fluent 的帖子并观看了演讲后,我得出了最终的解决方案:

   template< class Function, class... Args>
   using IsInvocable = std::enable_if_t < std::is_invocable_v<Function, Args...> >;

    template< class Function, class... Args, typename = IsInvocable<Function, Args...> >
    explicit ThreadHandle( const std::string & name, Function && f, Args &&... args ) {
        startWithName(name, f, args...);
    }

第一位只是将一些语法移动到一个通用的包含文件中,但总的来说,这更简单。我认为这很干净,几乎不需要解释,即使对于不熟悉使用类型特征的人来说也是如此。

问题

我想知道的是这个。我收到的所有三个答案都使用了更复杂的形式,如下所示:enable_if_t

std::enable_if_t<std::is_invocable_v<Function, Args...>, std::nullptr_t> = nullptr>

我不确定如果我可以这样做,他们为什么要这样做:

std::enable_if_t< std::is_invocable_v < Function, Args... > >

有影响吗?或者这仅仅是一个更复杂的问题 C++ 11,现在 C++ 14 和 17 允许更简单的形式?也许回复的人只是通过向我展示完整的表格来帮助我。

更让我困惑的是,其中一个答案是这样做的:

std::enable_if_t<!std::is_convertible_v<Function, std::string>, bool> = true>

另一个人这样做了:

std::enable_if_t<std::is_invocable_v<Function, Args...>, int> = 0>

我也不太明白这些含义。

任何帮助克服障碍都会很棒。我想在某些情况下我会想要更复杂的版本,所以更好地理解它会很好。

C++ SFINAE 类型特征

评论

2赞 François Andrieux 12/14/2021
std::enable_if_t< std::is_invocable_v < Function, Args... > >是当条件为 时。这适用于模板参数,但不适用于模板参数。在这种情况下,您可以改用它或其他一些简单类型,并分配一个默认值,这样用户就不必提供任何内容。我不确定这是否是适用于这里的具体原因,但这是我想到的第一个原因。voidtrueusing IsInvocable = void;void*
1赞 JHBonarius 12/14/2021
在 Stack overflow 上有许多关于 enable_if 和 SFINAE 的答案:这些答案中的任何一个都回答了您的问题吗?问答 1、问答 2.此外,cppreference 也有一些信息
0赞 StoryTeller - Unslander Monica 12/14/2021
这是最大的原因 stackoverflow.com/q/36499008/817643

答:

7赞 dfrib 12/14/2021 #1

词汇

// template-head
template<typename T = T{}>
//       ^^^^^^^^^^   ^^^- default template-argument
//           \ type template-parameter

// template-head
template<int i = 0>
//       ^^^^^   ^- default template-argument
//           \ non-type template-parameter  

默认模板参数不是函数模板类型的一部分

默认模板参数不是函数模板类型的一部分,这意味着不能使用以下方法:

// BAD: trying to define to SFINAE-mutually exclusive overloads.
template<typename T, typename = std::enable_if_t<some_predicate_v<T>>>
void f(T) {}

template<typename T, typename = std::enable_if_t<!some_predicate_v<T>>>
void f(T) {}

因为它们定义了相同的功能;例如,参见

了解详情。

...而不同类型的非类型模板参数可以用作替代参数

因此,当您不对其他相同的功能进行重载时,通常使用上述方法,而当您需要区分重载时,则使用其他系列。

// Variation A.
template<typename T,
         // non-type template parameter of type void*,
         // defaulted to nullptr 
         std::enable_if_t<some_predicate_v<T>>* = nullptr>
void f(T) {}

// OK: not the same function.
template<typename T,
         std::enable_if_t<!some_predicate_v<T>>* = nullptr>
void f(T) {}

// Variation B.
template<typename T,
         // non-type template parameter of type bool,
         // defaulted to true or false 
         std::enable_if_t<some_predicate_v<T>, bool> = true>
void f(T) {}

// OK: not the same function.
template<typename T,
         std::enable_if_t<!some_predicate_v<T>, bool> = true>
void f(T) {}

// Variation C.
template<typename T,
         // non-type template parameter of type int,
         // defaulted to 0
         std::enable_if_t<some_predicate_v<T>, int> = 0>
void f(T) {}

// OK not the same function.
template<typename T,
         std::enable_if_t<!some_predicate_v<T>, int> = 0>
void f(T) {}

// Variation D (uncommon/noisy).
template<typename T,
         // non-type template parameter of type std::nullptr_t,
         // defaulted to nullptr
         std::enable_if_t<some_predicate_v<T>, std::nullptr_t> = nullptr>
void f(T) {}

// OK: not the same function.
template<typename T,
         std::enable_if_t<!some_predicate_v<T>, std::nullptr_t> = nullptr>
void f(T) {}

请注意,对于变体 A,我们利用了第二个模板参数(通过别名模板的别名)默认为 .std::enable_if_tvoid