小编0xd*_*00d的帖子

if constexpr和requires-expression用于ad-hoc概念检查

让我们说,给定C++ 17 if constexpr和Concepts TS(例如,在最近的gcc版本中),我们想检查模板函数中的类型是否具有嵌套类型:

#include <iostream>

struct Foo { using Bar = int; };

template<typename T>
void doSmth(T)
{
    if constexpr (requires { typename T::Bar; })
        std::cout << "has nested! " << typename T::Bar {} << std::endl;
    else
        std::cout << "no nested!" << std::endl;
}

int main()
{
    doSmth(Foo {});
    //doSmth(0);
}
Run Code Online (Sandbox Code Playgroud)

概念的文档很少,所以我可能错了,但似乎就是这样(并且实例是在Wandbox上).

现在让我们考虑一下取消注释另一个doSmth调用时会发生什么.似乎有理由期望require-clause将评估false,并且将采取意志的else分支if constexpr.与此相反,gcc使这成为一个很难的错误:

prog.cc: In instantiation of 'void doSmth(T) [with T = int]':
prog.cc:17:13:   required from …
Run Code Online (Sandbox Code Playgroud)

c++ c++-concepts c++20

7
推荐指数
3
解决办法
400
查看次数

将SFINAE上下文中不正确的模板实例化的硬错误转换为软错误

假设我们给出了一个模板实例化Container<U, Args...>(想想Container是一个std::vector)和一个非模板类型T,我们需要检查是否可以调用push_back一个类型的对象Container<T>.这是使用探测器成语的代码:

#include <iostream>
#include <vector>
#include <set>
#include <string>
#include <type_traits>
#include <boost/iterator.hpp>
#include <boost/range.hpp>

template<typename, typename>
struct replace
{
    using type = struct Error;
};

template<template<typename...> class Container, typename U, typename T>
struct replace<Container<U>, T>
{
    using type = Container<T>;
};

template<typename Container, typename T>
using replace_t = typename replace<Container, T>::type;

template<typename Placeholder, template<typename...> class Op, typename... Args>
struct isDetected : std::false_type {};

template<template<typename...> class Op, typename... Args> …
Run Code Online (Sandbox Code Playgroud)

c++ templates sfinae c++11

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

用户定义与自动模板扣除指导优先级

假设我们有一个这样的类,带有用户定义的演绎指南:

template<typename T, typename... Args>
struct Foo
{
    Foo(Args&&...) { std::cout << "just Args: " << __PRETTY_FUNCTION__ << std::endl; }
    Foo(Args&&..., T&&) { std::cout << "Args and T: " << __PRETTY_FUNCTION__ << std::endl; }
};

template<typename... Args>
Foo(Args&&...) -> Foo<Void, Args...>;
Run Code Online (Sandbox Code Playgroud)

现在让我们尝试创建这个类的实例:Foo foo { 10 };.什么是推导出的模板参数以及将调用哪个构造函数?

经过一些实验后,它取决于编译器.即,GCC 7和铛6(从主干)似乎选择自动引导,实例化TintArgs用空包,因此输出是

Args and T: Foo<T, Args>::Foo(Args&& ..., T&&) [with T = int; Args = {}]
Run Code Online (Sandbox Code Playgroud)

另一方面,clang 5选择用户定义的指南:

just Args: Foo<Void, int>::Foo(Args &&...) [T = Void, …
Run Code Online (Sandbox Code Playgroud)

c++ templates template-argument-deduction c++17

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

使用惰性字节串读取大文件时减少内核开销

我正在读取一个大文件(1-10 GB)并计算一些简单的统计数据,比如计算一个字符。在这种情况下流式传输是有意义的,所以我使用了 lazy ByteStrings。特别是,我的main样子

import qualified Data.ByteString.Lazy as BSL

main :: IO ()
main = do
  contents <- BSL.readFile "path"
  print $ computeStats contents
Run Code Online (Sandbox Code Playgroud)

computeStats在这种情况下,细节可能并不重要。

使用 运行它时+RTS -sstderr,我看到了这个:

MUT     time    0.938s  (  1.303s elapsed)
Run Code Online (Sandbox Code Playgroud)

请注意 CPU 时间和已用时间之间的差异。除此之外,运行 under/usr/bin/time显示类似的结果:

0.89user 0.45system 0:01.35elapsed
Run Code Online (Sandbox Code Playgroud)

我正在测试的文件在 中tmpfs,因此实际磁盘性能不应该是一个因素。

system在这种情况下如何减少时间?我尝试明确设置文件句柄的缓冲区大小(对运行时间没有统计上的显着影响)以及mmaping 文件并将其包装成一个ByteString(运行时间实际上变得更糟)。还有什么值得尝试的?

linux io haskell

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

功能组成和forall'ed类型

假设我们有一些像这样的代码,哪些类型很好:

{-# LANGUAGE RankNTypes #-}

data Foo a

type A a = forall m. Monad m => Foo a -> m ()
type PA a = forall m. Monad m => Foo a -> m ()
type PPFA a = forall m. Monad m => Foo a -> m ()

_pfa :: PPFA a -> PA a
_pfa = _pfa

_pa :: PA a -> A a
_pa = _pa

_pp :: PPFA a -> A a
_pp x = …
Run Code Online (Sandbox Code Playgroud)

haskell rank-n-types

5
推荐指数
1
解决办法
297
查看次数

将存在主义提升到类型级别

tl; dr:我正在尝试重写一些在 Haskell 中具有 sigma 类型列表的依赖类型代码,但我似乎无法为存在对象生成单例,换句话说,这段代码失败了:

data Foo :: Type where
  Foo :: forall foo. Sing foo -> Foo

$(genSingletons [''Foo])
Run Code Online (Sandbox Code Playgroud)

更长的版本如下。

假设这个 Idris 代码作为模型:

data AddrType = Post | Email | Office

data AddrFields : AddrType -> Type where
  PostFields : (city : String) -> (street : String) -> AddrFields Post
  EmailFields : (email : String) -> AddrFields Email
  OfficeFields : (floor : Int) -> (desk : Nat) -> AddrFields Office

Addr : Type
Addr = (t : AddrType …
Run Code Online (Sandbox Code Playgroud)

haskell dependent-type singleton-type idris

5
推荐指数
1
解决办法
325
查看次数

使用存在将值提升到类型而不损害性能

我正在尝试对序列进行可组合折叠(类似于 foldl 库),但是在类型级别完成了更多的工作,希望编译器能够更轻松地进行内联和 CSE 处理(这些希望不是根据一些实验没有根据)。

为此,我有一个类型类(这是一个非常简化的示例):

class Statistic a where
  type StateOf a = k | k -> a
  type ResultOf a = k | k -> a
  extract :: StateOf a -> ResultOf a
  computeStep :: StateOf a -> Double -> StateOf a
  ...
Run Code Online (Sandbox Code Playgroud)

我也有几个基本实例

data Stats = Min | Max | Avg | Stddev

instance Statistic 'Min where ...
instance Statistic 'Max where ...
...
Run Code Online (Sandbox Code Playgroud)

以及一个组合实例

data a ::: b = a ::: b

instance (Statistic a, Statistic …
Run Code Online (Sandbox Code Playgroud)

performance haskell existential-type dependent-type

5
推荐指数
0
解决办法
167
查看次数

将域建模为GADT类型并为其提供do-sugar

假设我们想要构建一个表示典型操作的类型,比如说,一个无锁算法:

newtype IntPtr = IntPtr { ptr :: Int } deriving (Eq, Ord, Show)

data Op r where 
  OpRead :: IntPtr -> Op Int
  OpWrite :: IntPtr -> Int -> Op ()

  OpCAS :: IntPtr -> Int -> Int -> Op Bool
Run Code Online (Sandbox Code Playgroud)

理想情况下,我们希望使用方便do注释在此模型中表示一些算法,例如(假设相应read = OpReadcas = OpCAS出于美学原因)维基百科示例的以下几乎字面翻译:

import Prelude hiding (read)
import Control.Monad.Loops

add :: IntPtr -> Int -> Op Int
add p a = snd <$> do
  iterateUntil fst $ do …
Run Code Online (Sandbox Code Playgroud)

haskell gadt

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

线程安全地初始化一个指针一次

例如,我正在编写一个库函数,count_char(const char *str, int len, char ch)它检测正在运行的 CPU 支持的 SIMD 扩展并将调用分派到 AVX2 或 SSE4.2 优化版本。因为我想避免cpuid每次调用执行几个指令的惩罚,所以我试图在第一次调用函数时只执行一次(可能由不同的线程同时调用)。

在 C++ 领域,我只会做类似的事情

int count_char(const char *str, int len, char ch) {
    static const auto fun_ptr = select_simd_function();
    return (*fun_ptr)(str, len, ch);
}
Run Code Online (Sandbox Code Playgroud)

并依赖于 C++ 语义static来保证它只被调用一次而没有任何竞争条件。但是在纯 C 中做到这一点的最佳方法是什么?

这是我想出的:

  1. 使用原子变量(也存在于 C 中)——相当容易出错并且更难维护。
  2. 使用pthread_once- 不确定它有什么开销,而且它可能会给 Windows 带来麻烦。
  3. 强制库用户调用另一个库函数来初始化指针——简而言之,它在我的情况下不起作用,因为这实际上是另一种语言的库的 C 位。
  4. 将指针对齐 8 个字节并依赖 x86 字大小的访问是原子的——不可移植到其他架构(我以后是否应该实现一些 PowerPC 或特定于 ARM 的 SIMD 版本,说),技术上 UB(至少在 C++ 中)。
  5. 使用线程本地存储并标记fun_ptrthread_local …

c multithreading initialization

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

类型类和 levity 多态性

假设我有一个可以取消装箱/重新装箱的值的类:

class Unboxable a (rep :: RuntimeRep) (unboxedTy :: TYPE rep) | a -> rep, a -> unboxedTy where
  unbox :: a -> unboxedTy
  rebox :: unboxedTy -> a
Run Code Online (Sandbox Code Playgroud)

像这样的例子非常好:

instance Unboxable Int 'IntRep Int# where
  unbox (I# w) = w
  rebox = I#
Run Code Online (Sandbox Code Playgroud)

但是如果我尝试支持不可装箱值的元组,例如

instance (Unboxable a repa unboxedTyA, Unboxable b repb unboxedTyB)
       => Unboxable (a, b) ('TupleRep '[ repa, repb ]) (# unboxedTyA, unboxedTyB #) where
  unbox (a, b) = (# unbox a, unbox b #)
  rebox (# …
Run Code Online (Sandbox Code Playgroud)

haskell

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

对结构成员的临时绑定引用

我在一些代码库上尝试了 Coverity,我在一个类似于

struct Foo
{
    std::string name;
};

Foo getFoo();
//...
const auto& name = getFoo().name;
useName(name);
Run Code Online (Sandbox Code Playgroud)

这个代码有效吗?

我的直觉是它确实是无效的。但是,在搜索证明时,我遇到了[class.temporary]/6.4,这似乎表明它实际上格式良好。然而,Coverity 发出警告,Coverity 肯定是由一些比我更能解释标准的聪明人写的。

发出的具体 Coverity 警告是

取消引用返回的或超出范围的堆栈指针将在其作用域之后或函数返回之后访问堆栈上的无效位置。

在whateverSurroundingFunction() 中:指向在范围外返回或使用的局部堆栈变量的指针(CWE-562)

在随后的使用name。前面的警告是

out_of_scope:类型的临时变量Foo超出范围

和一种MRE的是这个(荣誉给@ user4581301在评论)。


SO 有一堆关于临时绑定引用的问题,但我所看到的每个问题都有略微不同的上下文,因此这里又出现了另一个问题。

c++ lifetime language-lawyer temporary-objects coverity

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