小编sky*_*ack的帖子

类型擦除和可变模板成员函数

下面的例子是一个很小的,也许不是一个众所周知的成语的例子.
它编译并且它是如此丑陋,以便能够保持最小,因为问题不是关于成语本身.

struct Foo {
    virtual void fn() = 0;
};

template<class T>
struct Bar: public Foo {
    void fn() override {
        T{}.fn();
    }
};

struct S {
    void fn() { }
};

int main() {
    Foo *foo = new Bar<S>{};
    foo->fn();
}
Run Code Online (Sandbox Code Playgroud)

我一小时前就在苦苦思索的是如何改变它(甚至,如果存在替代习语),引入一个可变参数模板成员方法.
显然,我不能修改类的fn功能Foo,因为它是虚拟的,虚拟说明符不与模板一起使用.这对于fn规范是有效的Bar,因为它必须以某种方式覆盖基类中的那个.

注意.

因为我强烈怀疑这个问题可能是有史以来最伟大的XY问题之一,我还想简要介绍一下实际问题.

我有一个暴露两个模板化成员方法的类:

  • 第一个接受一个T不立即使用的模板类,而是应该以某种方式存储,以便以后使用.

  • 第二个接受一个可变数量的参数(它实际上是一个可变参数的模板成员函数),这些参数应该完美地转发到新创建的实例T.

嗯,问题要复杂得多,但这是一个很好的近似,应该让你知道目标是什么.

编辑

我猜它在某种程度上类似于高阶函数.
我的意思是,解决这个问题的确是一个模板化的函数来绑定第一个参数,但据我所知,这是不可能的,以及我迄今为止探索过的任何其他方法.
任何表达相同概念的可行解决方案?

c++ templates type-erasure variadic-templates c++11

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

文字运算符模板:为什么不用字符串?

再一次,在回答另一个问题时,我忘记了(我的错),只有在找到整数或浮点文字时才从声明集中选取文字运算符模板.

举个例子:

template <char... C>
constexpr int operator "" _x() {
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

它可以用作10_x,但不能既不foo_x用作"foo"_x也不能用.

除了明显的原因是因为标准说明了,在处理字符串文字时,他们不被考虑的技术原因(如果有的话)是什么?

我也找到了一个建议(好吧,不完全相同,但它提出了一个想法),但仍然不是一个选择.
什么阻止他们用于字符串?

c++ templates user-defined-literals c++11

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

检查防护参数包是否是导致格式错误的程序?

不止一次(甚至在SO上)我见过这样的代码:

template<typename U, typename... G, typename T = Traits<U>>
struct {
    static_assert(sizeof...(G) == 0, "!");
    // ...
};
Run Code Online (Sandbox Code Playgroud)

或这个:

template<typename T, typename... G, typename = std::enable_if_t<condition<T>>
void func(T &&t) {
    static_assert(sizeof...(G) == 0, "!");
    // ....
}
Run Code Online (Sandbox Code Playgroud)

目的是避免用户做这样的事情来打破游戏规则:

template<typename T, typename = std::enable_if_t<std::is_same<T, int>>
void func(T &&t) {
    // ....
}

// ...

func<int&, void>(my_int);
Run Code Online (Sandbox Code Playgroud)

使用guard参数包时,无法覆盖默认值.
另一方面,对尺寸的检查避免了无用参数的专业化污染.

无论如何,由于[temp.res/8],我们有:

该程序格式错误,无需诊断,如果:
[...]
- 可变参数模板的每个有效专业化都需要一个空模板参数包,或
[...]

因此,包含上述片段的程序是否格式错误?

c++ templates language-lawyer variadic-templates

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

缩小,未评估的上下文和模板功能

请考虑以下代码:

auto f() -> decltype(int{0.}, void()) { }
int main() { f(); }
Run Code Online (Sandbox Code Playgroud)

它没有编译(如预期)并出现错误:

在{}内缩小'0.0'从'double'到'int'的转换

海湾合作委员会和克朗都同意这一点.
现在考虑以下代码:

template <typename T>
auto f(T) -> decltype(int{0.}, void()) { }

int main(){
    f(0);
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,clang 3.9返回错误,GCC 6.2编译时没有错误.

在功能模板的情况下是否应该接受缩小转换或者是GCC的错误?


我打算向GCC打开一个问题,我想它应该无法编译,但我想知道我是否遗漏了一些关于函数模板的重要信息.

c++ templates decltype narrowing c++11

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

std :: list和std :: for_each:我的结局在哪里?

请考虑以下最小示例:

#include <functional>
#include <algorithm>
#include <list>

int main() {
    std::list<std::function<void()>> list;
    list.push_back([&list](){ list.push_back([](){ throw; }); });
    std::for_each(list.cbegin(), list.cend(), [](auto &&f) { f(); });
}
Run Code Online (Sandbox Code Playgroud)

它在运行时编译并抛出异常.
我的猜测是只有第一个lambda被执行std::for_each,但显然我错了:如果我在列表的末尾添加另一个lambda,迭代也会达到lambda.

让我们恢复示例(push_front而不是push_backcrbegin/ crend而不是cbegin/ cend):

#include <functional>
#include <algorithm>
#include <list>

int main() {
    std::list<std::function<void()>> list;
    list.push_front([&list](){ list.push_front([](){ throw; }); });
    std::for_each(list.crbegin(), list.crend(), [](auto &&f) { f(); });
}
Run Code Online (Sandbox Code Playgroud)

由于前面的例子,我预计这也会编译和崩溃.
相反,它编译并且不会崩溃.这次,不执行推到列表前面的功能.

问题很简单:这是正确的吗?
为什么两个例子如此违反直觉?

在第一种情况下,我期待一些不同的东西,我错了,这不是问题.
无论如何,我希望两个循环之间的一致性.我的意思是,第二个函数在一个案例中执行,而在另一个案例中不执行,但我在两种情况下都是从开始结束迭代.
我的推理出了什么问题?

c++ foreach iterator stdlist

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

非捕获通用lambda是否应该衰减到函数指针?

请考虑以下代码:

int main() {
    auto l = [](auto){};
    void(*p)(int) = l;
}
Run Code Online (Sandbox Code Playgroud)

它与GCCclang一起工作得很好.
让我们考虑以下略微修改的版本:

int main() {
    auto l = [](auto...){};
    void(*p)(int) = l;
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,clang仍然接受它,而GCC 拒绝它.

是否有任何理由拒绝此代码或是否是编译器的错误?


我打算提出一个问题,但我想知道是否有任何提案可以由其中一个提出,而不是由另一个提出.

c++ gcc clang generic-lambda c++14

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

为什么并行的for_each需要正向迭代器?

我正在设计一个遍历多个容器的迭代器,因此将代理对象作为返回类型。因此,最好的办法是成为输入迭代器(这是因为前向迭代器需要reference是实际的引用类型,而据我所知,这对于输入迭代器而言并非如此)。

(让我说)plain for_each就像我的迭代器一样具有魅力。
但是,当我查看其并行版本时,我发现它仅接受转发迭代器。因此,我不能使用复杂的迭代器来返回代理对象,这很烦人。
另一方面,我在网上寻找其他著名的实现,这并不像我最初想象的那么普遍-例如,英特尔®TBB为每个接受输入迭代器的设备提供了自己的并行处理。

那么我的问题是:为什么并行不能std::for_each与输入迭代器一起使用?
我看不到它们是正向迭代器的意义,因为乍一看它即使在输入迭代器中也能正常工作。我想念什么?

c++ std c++-standard-library language-lawyer c++17

7
推荐指数
2
解决办法
260
查看次数

是否可以保证std :: reference_wrapper的大小?

考虑以下情况:我有足够的存储空间来托管a void *并因此就地构造一个指针。
是否可以保证相同的存储空间足够大,以便始终存储一个std::reference_wrapper

某种(出于我的想法而写,只是为了理解我的意思):

std::aligned_storage_t<sizeof(void *), alignof(void *)> storage;
// ...
int value = 0;
new (&storage) std::reference_wrapper<int>{value};
Run Code Online (Sandbox Code Playgroud)

通过快速而肮脏的测试,我发现在我的机器上这是有效的,即与的大小std::reference_wrapper相符void *。但是,在不同平台上可能是这种情况。同时,我在标准中找不到关于和的大小的任何线索,std::reference_wrapper而且我想知道它的实现是否已定义或是否有任何保证。


为了提供上下文,我正在围绕不同类型(类似于std::any)的不透明包装器进行包装,该包装器执行小型对象优化以避免可能的分配。
收到时std::reference_wrapper,我想使用与用于区别sizeof(T) > sizeof(void *)其他情况的路径不同的路径。但是,我不知道我是否可以就地复制包装器的构造,或者在这种情况下是否还应该依靠分配。

c++ language-lawyer reference-wrapper c++17

7
推荐指数
2
解决办法
125
查看次数

多个参数包 - 如何?

我有以下问题:

#include <vector>
#include <tuple>

using namespace std;

template< size_t... N_i, typename Ts... >
class A
{
  // ...

  private:
    std::vector<size_t> _v = { N_i... };
    std::tuple<Ts...> _t;
};

int main()
{
  A<1> a;
}
Run Code Online (Sandbox Code Playgroud)

如您所见,我尝试将多个参数包定义为类的模板参数A.
不幸的是,代码无法编译:

错误:'Ts'之前的预期嵌套名称说明符

如何为此示例定义多个参数包?

c++ templates variadic-templates c++14

6
推荐指数
2
解决办法
1387
查看次数

在模板中获取函数返回类型

如何为传递给模板的任何函数获取返回类型?
我不知道如何转换template<typename T>template<typename Result, typename Args...>:

template<typename T>
void print_name(T f)
{
    static_assert(internal::is_function_pointer<T>::value
            || std::is_member_function_pointer<T>::value,
            "T must be function or member function pointer.");
    typename decltype(f(...)) Result; // ???
    typename std::result_of<T>()::type Result; // ???
    printf("%s\n", typeid(Result).name());
}

void f_void() {}
int f_int(int x) { return 0; }
float f_float(int x, int y) { return 0.f; }
struct X { int f(int x, float y) { return 0; } };

int main()
{
    print_name(f_void);
    print_name(f_int);
    print_name(f_float);
    print_name(&X::f);
    return …
Run Code Online (Sandbox Code Playgroud)

c++ templates c++14

6
推荐指数
2
解决办法
2264
查看次数