标签: void-t

C++ 模板 - 完整指南:了解有关 decltype 和返回类型的脚注注释

C++ 模板第二版- 完整指南在第 435 页包含以下代码

#include <string>
#include <type_traits>

template<typename T, typename = void>
struct HasBeginT : std::false_type {};

template<typename T>
struct HasBeginT<T, std::void_t<decltype(std::declval<T>().begin())>>
    : std::true_type {};
Run Code Online (Sandbox Code Playgroud)

和用于测试调用 adecltype(std::declval<T>().begin())是否有效的注释。.begin()T

这一切都有道理,我想……

令我震惊的是脚注中的评论:

除此之外,与其他上下文中的调用表达式不同,它不需要非引用、非返回类型来完成。使用相反,确实增加了调用返回类型完整的要求,因为返回值不再是操作数的结果。decltype(call-expression)voiddecltype(std::declval<T>().begin(), 0)decltype

我不太明白。

为了尝试使用它,我尝试使用以下代码查看它对voidmember的行为begin

struct A {
    void begin() const;
};

struct B {
};

static_assert(HasBeginT<A>::value, "");
static_assert(!HasBeginT<B>::value, "");
Run Code Online (Sandbox Code Playgroud)

但无论有没有 . ,这两个断言都通过了, 0

c++ templates decltype c++17 void-t

12
推荐指数
1
解决办法
455
查看次数

使用void_t和受保护的嵌套类进行基于SFINAE的检测

我最近在clang和gcc之间遇到了关于void_t属性检测和受保护/私有类信息的一些不同行为.考虑一个类型特征,定义如下:

#include <type_traits>

template<typename T, typename = void>
constexpr const bool has_nested_type_v = false;

template<typename T>
constexpr const bool has_nested_type_v
<T, std::void_t<typename T::type>> = true;
Run Code Online (Sandbox Code Playgroud)

给定具有受保护或私有嵌套type类和简单程序的示例类型

#include "has_nested_type.hpp"
#include <iostream>

struct Protected {
protected:
  struct type{};
};

struct Private {
private:
  struct type{};
};

int main() {
  std::cout << "Protected: " 
            << (has_nested_type_v<Protected> ? "detected" : "not detected")
            << std::endl;
  std::cout << "Private: " 
            << (has_nested_type_v<Private> ? "detected" : "not detected")
            << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
  • clang成功编译失败的检测(如预期的那样).该程序,编译和输出上再现wandbox 这里 …

c++ gcc detection c++17 void-t

7
推荐指数
1
解决办法
211
查看次数

SFINAE`std :: void_t`类模板专门化

使用SFINAE,我需要检测容器的某些属性。

例如:

#include <type_traits>
#include <vector>

template <typename Container, typename = void>
struct Trait {};

template <typename Container>
struct Trait<
    Container,
    std::enable_if_t<std::is_integral_v<typename Container::value_type>>> {
  static constexpr bool foo = false;
};

template <typename Container>
struct Trait<
     Container, 
     std::enable_if_t<std::is_floating_point_v<typename Container::value_type>>> {
  static constexpr bool foo = true;
};

static_assert(Trait<std::vector<int>>::foo == false);
static_assert(Trait<std::vector<double>>::foo == true);
Run Code Online (Sandbox Code Playgroud)

上面的代码可以按预期进行编译和运行(在clanggcc上)。在这里检查

但是,如果我稍加修改将模板类型包装在里面的代码std::void_t

template <typename Container>
struct Trait<
    Container,
    std::void_t<std::enable_if_t<std::is_integral_v<typename Container::value_type>>>> {
  static constexpr bool foo …
Run Code Online (Sandbox Code Playgroud)

c++ templates sfinae c++17 void-t

7
推荐指数
0
解决办法
85
查看次数

C++20 概念是否取代其他形式的约束?

C++20 已经登陆,带来了概念。如果一个项目现在开始并且仅针对 C++20 和更高版本的标准,那么说以前的约束形式现在被概念和子句取代是否合适requires

是否存在某些情况下enable_ifvoid_t仍然需要,而概念无法替代它们?

例如,std::bit_cast被限制为要求ToFrom类型具有相同的大小,并且两种类型都可以轻松复制。

来自 cppreference:

仅当 sizeof(To) == sizeof(From) 并且 To 和 From 都是 TriviallyCopyable 类型时,此重载才参与重载决策。

MSVC 标准库通过enable_if_t表达式来限制这一点,而 libcxx 选择子句requires

微软VC:

enable_if_t<conjunction_v<bool_constant<sizeof(_To) == sizeof(_From)>, is_trivially_copyable<_To>, is_trivially_copyable<_From>>, int> = 0
Run Code Online (Sandbox Code Playgroud)

libcxx:

requires(sizeof(_ToType) == sizeof(_FromType) &&
         is_trivially_copyable_v<_ToType> &&
         is_trivially_copyable_v<_FromType>)
Run Code Online (Sandbox Code Playgroud)

它们通过不同的语言特征执行相同的逻辑运算。

重申我的问题,是否存在无法从一种约束方法转换为另一种约束方法的情况?我知道有很多东西概念requires可以做到enable_if和/或void_t不能做到,但是从另一个方向看也可以这么说吗?针对 C++20 及更高版本的全新代码库是否需要依赖这些旧的语言结构?

c++ enable-if c++-concepts c++20 void-t

6
推荐指数
1
解决办法
418
查看次数

混合void_t和可变参数模板?

请考虑以下代码:

template <class F, class... Args, class = std::void_t<>>
struct is_invokable
: std::false_type {};
template <class F, class... Args>
struct is_invokable<F, Args..., std::void_t<std::invoke_result_t<F, Args...>>>
: std::true_type {};
Run Code Online (Sandbox Code Playgroud)

目标是有一个特性,它能够判断类型F的可调参数是否可以使用类型的参数调用Args....

但是,它无法编译,因为:

error: parameter pack 'Args' must be at the end of the template parameter list
Run Code Online (Sandbox Code Playgroud)

在C++ 17中执行此操作的(优雅)方式是什么?

c++ sfinae variadic-templates c++17 void-t

4
推荐指数
1
解决办法
167
查看次数

结合void_t和enable_if?

在 中C++17void_t允许使用class/struct模板轻松执行 SFINAE:

template <class T, class = void>
struct test {
    static constexpr auto text = "general case";
};

template <class T>
struct test<T, std::void_t<decltype(std::begin(std::declval<T>())>> {
    static constexpr auto text = "has begin iterator";
};
Run Code Online (Sandbox Code Playgroud)

里面的东西void_t是一个类型。void_t我的问题是:当里面的内容是类型特征时,如何做同样的事情。使用enable_if效果很好:

template <class T>
struct test<T, std::void_t<std::enable_if_t<std::is_class_v<T>>> {
    static constexpr auto text = "is a class";
};
Run Code Online (Sandbox Code Playgroud)

是否有更短/更优雅的方式来写这个,或者“正确的方式”来做到这一点,真的是结合void_tand enable_if

sfinae enable-if template-meta-programming c++17 void-t

4
推荐指数
1
解决办法
2625
查看次数

C++ void_t SFINAE false_type true_type 无法获得专业化

这一切看起来很简单。

在我下面的代码中,对于 T=vector 来说,has_member_type::value 不应该是真的吗?对不起,如果它已经得到回答。我找了一会儿,但找不到答案。

#include <iostream>
#include <type_traits>

// has_value_type
template <typename, typename = std::void_t<>>
struct  has_value_type: std::false_type {};

template <typename T>
struct has_value_type<T, std::void_t<typename T::value_type>>: std::true_type {};

int main()
{
    std::cout << "bool: " << std::boolalpha << has_value_type<bool>::value << std::endl;
    std::cout << "vector_has: " << std::boolalpha << has_value_type<std::vector<int>>::value << std::endl;

    std::cout << "true_type: " << std::boolalpha << std::true_type::value << std::endl;
    std::cout << "false_type: " << std::boolalpha << std::false_type::value << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

bool: false
vector_has: false …
Run Code Online (Sandbox Code Playgroud)

c++ templates sfinae void-t

3
推荐指数
1
解决办法
144
查看次数

为什么这种检测习语的使用会导致 Clang 和 GCC 的编译错误不同,而 MSVC 不会导致编译错误

void_t尝试检测习惯用法时,我发现涉及减法运算符和 void* 的表达式会导致测试编译器中出现不同的错误。

GCC 10.2 及以下版本,无论使用 C++11、14、17 还是 20,似乎都将某些表达式视为硬错误而不是替换失败。

我正在使用以下(精简)示例

#include <type_traits>

template< class, class, class = void >
struct has_minus_void_t : std::false_type {};
template<class T, class U>
struct has_minus_void_t<T, U, std::void_t<
    decltype(T() - U())
    >> : std::true_type {};

static_assert(has_minus_void_t<int*,int*>::value, "int*");
static_assert(!has_minus_void_t<int*,void*>::value, "intvoid*");
static_assert(!has_minus_void_t<void*,int*>::value, "voidint*");
static_assert(!has_minus_void_t<void*,void*>::value, "void*");
Run Code Online (Sandbox Code Playgroud)

并且希望代码能够针对所有四种语言标准进行编译而不会出错(包含std::void_tC++17 之前的替代品,因此可以测试更多标准)但是

  • GCC 10.2 及以下版本抱怨最后两个断言
  • Clang 没有抱怨
  • MSVC 抱怨 int*/void* 组合

我试图搜索现有的错误报告,但找不到。

我想知道哪个编译器是正确的,为什么。

这是一个神箭

c++ standards-compliance decltype language-lawyer void-t

2
推荐指数
1
解决办法
62
查看次数

如何正确使用C ++ void_t?

我正在尝试void_t使用用法,但是以下代码给出了编译错误。is_funCompSstruct 中的typedef,所以我认为Comp::is_fun应该是有效的。

我有什么想念的吗?

template <typename T, typename Comp, typename = void_t<>>
class my_set
{
    public:
        my_set() : mem(5){}
        T mem;
};

template <typename T, typename Comp, void_t<typename Comp::is_fun> >
class my_set 
{
    public:
        my_set() : mem(10){}
        T mem;
};

struct CompS
{
    typedef int is_fun;
};

int main()
{
    my_set<int, CompS> a;
    std::cout << a.mem << std::endl;


    return 0;
}
Run Code Online (Sandbox Code Playgroud)

错误:

   voidt.cpp:17:38: error: ‘void’ is not a valid type for a template …
Run Code Online (Sandbox Code Playgroud)

c++ c++17 void-t

0
推荐指数
1
解决办法
88
查看次数