Using constexpr does not comply with C ++ 11 standard or did I find a compiler error?

I play with the constexpr keyword and encoded the following simple program:

#include <iostream>

using namespace std;

template<typename T>
constexpr bool is_equal(T const* array1, T const* array2, size_t len)
{
    return array1 == array2 || (len ? array1[len - 1] == array2[len - 1] && is_equal<T>(array1, array2, len - 1) : true);
}

template<typename T, size_t N1, size_t N2>
constexpr bool is_equal(T const (&array1)[N1], T const (&array2)[N2])
{
    return N1 == N2 && is_equal<T>(array1, array2, N1);
}



template<typename T, size_t N>
constexpr size_t arraylength(T const (&array)[N])
{
    return N;
}



constexpr size_t stringlength(char const* str, size_t len=0)
{
    return str ? (*str ? stringlength(str + 1, len + 1) : len) : 0;
}



constexpr size_t min(size_t one, size_t another)
{
    return one < another ? one : another;
}



constexpr size_t min_length(char const* str1, char const* str2)
{
    return min(stringlength(str1), stringlength(str2));
}



template<typename T, size_t N1, size_t N2>
constexpr size_t min_length(T const (&array1)[N1], T const (&array2)[N2])
{
    return min(N1, N2);
}



template<bool cond=false>
struct to_num
{
    enum {value=0};
};

template<>
struct to_num<true>
{
    enum {value=42};
};



template<size_t init>
struct two_times
{
    enum {value=init*2};
};



static constexpr char x[]{"One string"};
static constexpr char y[]{"One string"};

static constexpr int a[]{1,2,3,4};
static constexpr int b[]{1,2,3,4};

static constexpr int const* const c = &a[0];
static constexpr int const* const d = &b[0];

int main()
{
    cout << "The two literals are equal: " << to_num< is_equal("One string", "One string") >::value << endl; // COMPILES AND WORKS IN GCC BUT NOT IN CLANG
    cout << "The two variables x & y are equal: " << to_num< is_equal(x, y) >::value << endl;
    cout << "Pointers a & c are equal: " << to_num< a == c >::value << endl;
    cout << "Pointers b & c are equal: " << to_num< b == c >::value << endl;
    cout << "Pointers c & d are equal: " << to_num< c == d >::value << endl;
    cout << "The contents of c & d is the same: " << to_num< is_equal(c, d, arraylength(a)) >::value << endl;
    cout << "Pointers a & b are equal: " << to_num< a == b >::value << endl;
    cout << "The contents of a & b is the same: " << to_num< is_equal(a, b) >::value << endl;
    cout << "String x contains " << two_times< stringlength(x) >::value / 2 << " characters" << endl; // COMPILES AND WORKS IN CLANG BUT NOT IN GCC
    cout << "String literal contains " << two_times< stringlength("literal") >::value / 2 << " characters" << endl; // COMPILES AND WORKS IN CLANG BUT NOT IN GCC
    cout << "Array literal contains " << two_times< arraylength("literal") >::value / 2 << " values" << endl;
    return 0;
}

As a comment comment, some code compiles and works fine with g ++, but not with clang ++ and other compilers and works fine with clang ++, but not with g ++

Gcc error:

comaprison.cpp: In function ‘int main()’:
comaprison.cpp:97:62:   in constexpr expansion of ‘stringlength(((const char*)(& x)), 0ul)’
comaprison.cpp:29:55:   in constexpr expansion of ‘stringlength((str + 1u), (len + 1ul))’
comaprison.cpp:97:64: error: ‘((((const char*)(& x)) + 1u) != 0u)’ is not a constant expression
     cout << "String x contains " << two_times< stringlength(x) >::value / 2 << " characters" << endl;
                                                                ^
comaprison.cpp:97:64: note: in template argument for type ‘long unsigned int
comaprison.cpp:98:76:   in constexpr expansion of ‘stringlength(((const char*)"literal"), 0ul)’
comaprison.cpp:29:55:   in constexpr expansion of ‘stringlength((str + 1u), (len + 1ul))’
comaprison.cpp:98:78: error: ‘((((const char*)"literal") + 1u) != 0u)’ is not a constant expression
     cout << "String literal contains " << two_times< stringlength("literal") >::value / 2 << " characters" << endl; // COMPILES AND WORKS IN CLANG BUT NOT IN GCC
                                                                              ^
comaprison.cpp:98:78: note: in template argument for type ‘long unsigned int

and clang ++ one:

comaprison.cpp:89:55: error: non-type template argument is not a constant expression
    cout << "The two literals are equal: " << to_num< is_equal("One string", "One string") >::value << ...
                                                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
comaprison.cpp:8:19: note: subexpression not valid in a constant expression
    return array1 == array2 || (len ? array1[len - 1] == array2[len - 1] && is_equal<T>(array1, array2...
                  ^
comaprison.cpp:14:24: note: in call to 'is_equal(&"One string"[0], &"One string"[0], 11)'
    return N1 == N2 && is_equal<T>(array1, array2, N1);
                       ^
comaprison.cpp:89:55: note: in call to 'is_equal("One string", "One string")'
    cout << "The two literals are equal: " << to_num< is_equal("One string", "One string") >::value << ...
                                                      ^
1 error generated.

g ++ - "gcc version 4.8.1 (Ubuntu / Linaro 4.8.1-10ubuntu9)", clang ++ - "Ubuntu clang version 3.4-1ubuntu1 (trunk) (based on LLVM 3.4)"

Both on Linux x86_64.

Command lines:

clang++ -std=c++11 -o comaprison comaprison.cpp
g++ -std=c++11 -o comaprison comaprison.cpp

So, am I doing something outside the C ++ 11 standard with this code, or is something wrong with both compilers?

: g++, clang++, g++, clang++ g++, clang++

, , .

.

+4
2

Update:

  • GCC stringlength. :

    constexpr size_t stringlength(char const* str, size_t i=0)
    {
        return str ? (str[i] ? 1 + stringlength(str, i+1) : 0) : 0;
    }
    
  • GCC 4.6.3 :

    static constexpr int const* c = &a[0];
    static constexpr int const* d = &b[0];
    

    :

    static constexpr int* c = &a[0];
    static constexpr int* d = &b[0];
    

:

, GCC 4.6.3 .

int main()
{
    const char* a = "hallo";
    const char* b = "qallo";
    std::cout << is_equal(a,b,5) << std::endl;
    constexpr const char* c = "hallo";
    std::cout << is_equal(a,c,5) << std::endl;
}

, , , .

, constexpr.

+4

arraylength, , , GCC, GCC 4.7 4.8 constexpr const, GCC 4.6.

stringlength: GCC. , . , stringlength:

constexpr size_t stringlength(char const* str, size_t len=0)
{
  return str ? (str[len] ? stringlength(str, len + 1) : len) : 0;
}

, .

+2

Source: https://habr.com/ru/post/1534480/


All Articles