2015-02-24 13 views
10

Tôi đang cố gắng tạo một hàm constexpr sẽ nối một số mảng char tùy ý bằng cách làm việc từ câu trả lời sau của Xeo, nối hai mảng char.constexpr để nối hai hay nhiều chuỗi 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>{}); 
} 

nỗ lực của tôi vậy, đến nay:

#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; 
} 

Cả gcc 4.9 và kêu vang 3.5 cho lỗi chỉ ra rằng không có chức năng phù hợp với các concat bên trong biểu decltype có thể được tìm thấy.

kêu vang:

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. 

Các lỗi từ gcc và Clang cả chỉ ra rằng thứ hai mẫu concat chức năng không phải là một ứng cử viên cho concat trong biểu thức decltype. Chỉ có mẫu đầu tiên được xem xét. Tại sao vậy và làm thế nào để khắc phục điều này?

Edit: câu hỏi có liên quan về việc tại sao decltype không thể được sử dụng một cách đệ quy

trailing return type using decltype with a variadic template function

+0

Tôi có thiếu một cái gì đó nhưng những gì xảy ra với ' "hi" "có"' mà cũng sẽ nối các dây? –

+1

Theo như tôi có thể thấy, đây là một vấn đề tra cứu tên cơ bản: trong kiểu dấu trả về, hàm (template) chưa được khai báo và do đó không được tìm thấy bằng tra cứu không đủ tiêu chuẩn. ADL có thể tìm thấy nó, mặc dù. – dyp

+0

@dyp Ah, có ý nghĩa. ADL có thể tìm thấy nó? Làm sao? Chờ đã, không ... Tôi lại bối rối ... vấn đề xảy ra khi khởi tạo, không phải là tuyên bố. – Praxeolitic

Trả lời

11
template<size_t S> 
using size=std::integral_constant<size_t, S>; 

template<class T, size_t N> 
constexpr size<N> length(T const(&)[N]) { return {}; } 
template<class T, size_t N> 
constexpr size<N> length(std::array<T, N> const&) { return {}; } 

template<class T> 
using length_t = decltype(length(std::declval<T>())); 
constexpr size_t sum_string_sizes() { return 0; } 
template<class...Ts> 
constexpr size_t sum_string_sizes(size_t i, Ts... ts) { 
    return (i?i-1:0) + sum_sizes(ts...); 
} 

sau đó

template 
template<unsigned N1, unsigned N2, class... Us> 
constexpr auto 
concat(const char(&a1)[N1], const char(&a2)[N2], const Us&... xs) 
-> std::array<char, sum_string_sizes(N1, N2, length_t<Us>::value...)+1 > 
{ 
    return concat(a1, concat(a2, xs...)); 
} 

mà được thoát khỏi những đệ quy-trong- decltype.


Đây là một ví dụ đầy đủ sử dụng phương pháp trên:

template<size_t S> 
using size=std::integral_constant<size_t, S>; 

template<class T, size_t N> 
constexpr size<N> length(T const(&)[N]) { return {}; } 
template<class T, size_t N> 
constexpr size<N> length(std::array<T, N> const&) { return {}; } 

template<class T> 
using length_t = decltype(length(std::declval<T>())); 

constexpr size_t string_size() { return 0; } 
template<class...Ts> 
constexpr size_t string_size(size_t i, Ts... ts) { 
    return (i?i-1:0) + string_size(ts...); 
} 
template<class...Ts> 
using string_length=size< string_size(length_t<Ts>{}...)>; 

template<class...Ts> 
using combined_string = std::array<char, string_length<Ts...>{}+1>; 

template<class Lhs, class Rhs, unsigned...I1, unsigned...I2> 
constexpr const combined_string<Lhs,Rhs> 
concat_impl(Lhs const& lhs, Rhs const& rhs, seq<I1...>, seq<I2...>) 
{ 
    // the '\0' adds to symmetry: 
    return {{ lhs[I1]..., rhs[I2]..., '\0' }}; 
} 

template<class Lhs, class Rhs> 
constexpr const combined_string<Lhs,Rhs> 
concat(Lhs const& lhs, Rhs const& rhs) 
{ 
    return concat_impl(
    lhs, rhs, 
    gen_seq<string_length<Lhs>{}>{}, 
    gen_seq<string_length<Rhs>{}>{} 
); 
} 

template<class T0, class T1, class... Ts> 
constexpr const combined_string<T0, T1, Ts...> 
concat(T0 const&t0, T1 const&t1, Ts const&...ts) 
{ 
    return concat(t0, concat(t1, ts...)); 
} 

template<class T> 
constexpr const combined_string<T> 
concat(T const&t) { 
    return concat(t, ""); 
} 
constexpr const combined_string<> 
concat() { 
    return concat(""); 
} 

live example

+0

Tôi có một câu hỏi tiếp theo về vấn đề này, nếu bạn rất tốt bụng! http://stackoverflow.com/questions/39199564/c-constexpr-c-string-concatenation-parameters-used-in-a-constexpr-context – Short

+0

Ví dụ này không biên dịch cho Visual Studio 2015. .... .... \ src \ tsd.nav.sdk.mapdisplay.rmw \ app \ rmw_test \ test2.cpp (30): lỗi C2059: Syntaxfehler: "..." (tiếp theo) Ý tưởng? – user5024425

+0

@user MSVC có hỗ trợ 'decltype' kém. Tôi sẽ cố gắng, trên clsng/gcc, lấy mã của tôi và di chuyển các 'length_t'' decltype' bí danh và bubbling chúng lên về phía plades chúng được sử dụng để 'length' được sử dụng trực tiếp ở đó trong các loại trả về. – Yakk

Các vấn đề liên quan