首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >CTAD、initializer_list、非显式构造函数和函数调用

CTAD、initializer_list、非显式构造函数和函数调用
EN

Stack Overflow用户
提问于 2019-02-22 09:48:57
回答 2查看 216关注 0票数 5

基本上,我想要的是像multi_types std::initializer_list这样的东西

代码语言:javascript
复制
template<typename ...As>
struct Foo {
Foo(As...){}
};

template<typename ...As>
void f(Foo<As...>) {}

int main() {
  f(Foo{5, 3.f}); // 1) compile
  f({}); // 2) compile
  f({5, 3}); // 3) error
  f({5, 3.8}); // 4) error
  return 0;
}

我理解为什么第一个示例会编译。然而,我不明白为什么第二个编译,而其他的不编译。对我来说,第二个也不应该编译,如果第三和第四不编译。有没有办法进行第三次和第四次编译?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-03-17 18:33:17

然而,我不明白为什么第二个编译,而其他的不编译。

示例3和4无法编译,因为推导出的模板参数与您预期的不同。

当您将调用(f({5, 3}))写入函数模板template<typename ...As> void f(Foo<As...>)时,编译器需要推断任何缺少的模板参数(...As)。首先通过比较函数参数({5, 3})和函数参数(Foo<As...>),推导出这些缺少的模板参数。如果函数参数是初始化程序列表({5, 3}) 1,则函数参数(Foo<As...>)跳过模板参数演绎:

N4659 temp.deduct.call 17.8.2.1(1):初始化程序列表参数导致参数被视为非推导的上下文(17.8.2.5)。N4659 temp.deduct.type 17.8.2.5(5.6):非推导的上下文包括一个函数参数,其相关的参数是一个初始化器列表(11.6.4) .

由于尾随模板参数pack (As...)不是由任何函数参数推导出来的,因此它被推断为空:

N4659 temp.arg.explicit 17.8.1(3):未导出的尾随模板参数包(17.5.3)将被推导为模板参数的空序列。

对于void f(Foo<>).,编译器推断模板参数是<> (空),因此调用的专门化是。重要:不管初始化程序列表中的是什么,都会选择此专门化。这就解释了编译器提供的诊断:

嘎吱声: 错误:对“f”的调用没有匹配函数 注意:带有As = <>的候选函数不可行:不能将初始化程序列表参数转换为“Foo<>” GCC: 错误:无法将“{5,3}”从“”转换为“Foo<>” MSVC: 错误C2664:'void f<>(Foo<>)':无法将参数1从“初始化程序列表”转换为“Foo<>” 注意:任何构造函数都不能接受源类型,或者构造函数重载解析不明确。

在函数调用中,函数参数使用函数参数的复制初始化来初始化.以下语句使用与示例初始化f参数相同的规则初始化变量

代码语言:javascript
复制
Foo<> x = {};        // Example 2
Foo<> x = {5, 3};    // Example 3
Foo<> x = {5, 3.8};  // Example 4

简而言之,如果函数参数既不是std::initializer_list<T>也不是T[n]

票数 1
EN

Stack Overflow用户

发布于 2019-03-17 19:00:33

有没有办法进行第三次和第四次编译?

我认为没有办法更改fFoo来编译第四个示例。

要编译第三个示例,可以添加f的重载,该重载包含一个数组:

代码语言:javascript
复制
#include <cstddef>
#include <utility>

#define EXPLICIT_TEMPLATE_ARGUMENTS 1
//#define EXPLICIT_TEMPLATE_ARGUMENTS 0

#if EXPLICIT_TEMPLATE_ARGUMENTS
template<class T, std::size_t>
struct identity {
    using type = T;
};
#endif

template<class ...As>
struct Foo {
    Foo(As...);
};

template<class ...As>
void f(Foo<As...>);

template<class A, std::size_t N, std::size_t ...Indexes>
void f_helper(A const (&as)[N], std::index_sequence<Indexes...>) {
    static_assert(N == sizeof...(Indexes));
#if EXPLICIT_TEMPLATE_ARGUMENTS
    // Example pack expansions:
    // return f<>(Foo<>{});
    // return f<A>(Foo<A>{as[0]});
    // return f<A, A>(Foo<A, A>{as[0], as[1]});
    return f<typename identity<A, Indexes>::type...>(Foo<typename identity<A, Indexes>::type...>{as[Indexes]...});
#else
    // Example pack expansions:
    // return f(Foo{});
    // return f(Foo{as[0]});
    // return f(Foo{as[0], as[1]});
    return f(Foo{as[Indexes]...});
#endif
}

// Call as: f({x, y, z})
template<class A, std::size_t N>
void f(A const (&as)[N]) {
    return f_helper<A, N>(as, std::make_index_sequence<N>());
}

int main() {
  f(Foo{5, 3.f}); // 1) compile
  f({}); // 2) compile
  f({5, 3}); // 3) compile (was: error)
  f({5, 3.8}); // 4) error

  return 0;
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54824308

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档