【发布时间】:2015-02-24 23:36:37
【问题描述】:
我正在尝试创建一个 constexpr 函数,该函数将通过 Xeo 的以下答案连接任意数量的 char 数组,该答案连接两个 char 数组。
https://stackoverflow.com/a/13294458/1128289
#include <array>
template<unsigned... Is> struct seq{};
template<unsigned N, unsigned... Is>
struct gen_seq : gen_seq<N-1, N-1, Is...>{};
template<unsigned... Is>
struct gen_seq<0, Is...> : seq<Is...>{};
template<unsigned N1, unsigned... I1, unsigned N2, unsigned... I2>
constexpr std::array<char const, N1+N2-1> concat(char const (&a1)[N1], char const (&a2)[N2], seq<I1...>, seq<I2...>){
return {{ a1[I1]..., a2[I2]... }};
}
template<unsigned N1, unsigned N2>
constexpr std::array<char const, N1+N2-1> concat(char const (&a1)[N1], char const (&a2)[N2]){
return concat(a1, a2, gen_seq<N1-1>{}, gen_seq<N2>{});
}
到目前为止我的尝试:
#include <iostream>
#include <array>
template<unsigned... Is> struct seq{};
template<unsigned N, unsigned... Is>
struct gen_seq : gen_seq<N-1, N-1, Is...>{};
template<unsigned... Is>
struct gen_seq<0, Is...> : seq<Is...>{};
template<unsigned N1, unsigned... I1, unsigned N2, unsigned... I2>
constexpr const std::array<char, N1+N2-1>
concat_impl(
const char (&a1)[N1], const char (&a2)[N2], seq<I1...>, seq<I2...>)
{
return {{ a1[I1]..., a2[I2]... }};
}
template<unsigned N1, unsigned N2>
constexpr const std::array<char, N1+N2-1>
concat(const char (&a1)[N1], const char (&a2)[N2])
{
return concat_impl(a1, a2, gen_seq<N1-1>{}, gen_seq<N2>{});
}
template<unsigned N1, unsigned N2, class... Us>
constexpr auto
concat(const char(&a1)[N1], const char(&a2)[N2], const Us&... xs)
-> std::array<char, N1 + decltype(concat(a2, xs...))::size() - 1>
{
return concat(a1, concat(a2, xs...));
}
int main()
{
auto const s = concat("hi ", "there!");
std::cout << s.data() << std::endl;
// compile error:
auto const t = concat("hi ", "there ", "how ", "are ", "you?");
std::cout << t.data() << std::endl;
}
gcc 4.9 和 clang 3.5 都给出错误,表明在 decltype 表达式中找不到与 concat 匹配的函数。
叮当声:
error: no matching function for call to 'concat'
auto const t = concat("hi ", "there ", "how ", "are ", "you?");
^~~~~~
ctconcat.cpp:105:16: note: candidate template ignored: substitution failure [with N1 = 4, N2 = 7, Us = <char [5], char [5], char [5]>]: no matching function for call to 'concat'
constexpr auto concat(const char(&a1)[N1], const char(&a2)[N2], const Us&... xs) -> std::array<char, N1 + decltype(concat(a2, xs...))::size() - 1>
^ ~~~~~~
ctconcat.cpp:62:43: note: candidate function template not viable: requires 2 arguments, but 5 were provided
constexpr const std::array<char, N1+N2-1> concat(const char (&a1)[N1], const char (&a2)[N2])
^
1 error generated.
gcc 和 clang 的错误都表明第二个concat 函数模板不是decltype 表达式中concat 的候选对象。仅考虑第一个模板。为什么会这样?我该如何解决?
编辑:关于为什么decltype不能递归使用的相关问题
trailing return type using decltype with a variadic template function
【问题讨论】:
-
我错过了什么,但
"hi " "there!"有什么问题,它也会连接字符串? -
据我所知,这是一个基本的名称查找问题:在 trailing-return-type 中,函数(模板)尚未声明,因此无法通过纯非限定查找找到.不过,ADL 可以找到它。
-
@dyp 啊,有道理。 ADL能找到吗?如何?等等,不……我又糊涂了……问题发生在实例化时,而不是声明时。
-
@NeilKirk 这适用于无法选择的情况。直到编译时才知道字符串(与模板的作者身份时间相反)。
-
ADL 找不到
concat,因为该函数模板不与全局命名空间关联,例如通过其函数参数或模板参数的类型。为了在依赖模板参数的调用中查找函数名称,ADL 也将从实例化点开始执行,即在声明完成并且可以找到函数模板(其名称)之后。例如,尝试添加一个模板参数,该参数填充了在全局命名空间中声明的类类型。参见例如stackoverflow.com/a/21815838
标签: c++ templates c++11 constexpr