Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Wading through template instantiation errors for allocator

113 views
Skip to first unread message

Frederick Gotham

unread,
Jan 3, 2020, 10:04:19 AM1/3/20
to

My GNU C++ compiler version 7.4.0 for Ubuntu won't compile the following code and I don't know why.

If I remove the second template parameter, i.e. "size_t capacity", then it works fine.

I wonder if another compiler will compile it?

This code is for a new kind of allocator that uses global (i.e. static duration) memory.

#include <cstddef> /* size_t */
#include <new> /* Only for bad_alloc */

template<typename T, std::size_t capacity>
class StaticAllocator {
public:
typedef T value_type;

protected:

static T buf[capacity];

public:

T *allocate(std::size_t const n)
{
if (n > capacity)
throw std::bad_alloc();

return buf;
}

void deallocate(T *, std::size_t)
{
/* Do Nothing */
}
};

template<typename T, std::size_t capacity>
T StaticAllocator<T,capacity>::buf[capacity];

using std::size_t;

#include <vector>
using std::vector;

#include <iostream>
using std::cout;
using std::endl;

auto main(void) -> int
{
vector< char, StaticAllocator<char, 4> > v;

v.push_back('a');
v.push_back('b');
v.push_back('c');
v.push_back('d');

for (auto const &elem : v)
cout << elem << endl;

vector< char, StaticAllocator<char, 4> > v2;

v2.push_back('x');
v2.push_back('y');
v2.push_back('z');

for (auto const &elem : v2)
cout << elem << endl;

// Now try the first vector again

for (auto const &elem : v)
cout << elem << endl;
}


Melzzzzz

unread,
Jan 3, 2020, 11:57:57 AM1/3/20
to
On 2020-01-03, Frederick Gotham <cauldwel...@gmail.com> wrote:
>
> My GNU C++ compiler version 7.4.0 for Ubuntu won't compile the following code and I don't know why.
>
> If I remove the second template parameter, i.e. "size_t capacity", then it works fine.
>
> I wonder if another compiler will compile it?
>
> This code is for a new kind of allocator that uses global (i.e. static duration) memory.
>
> #include <cstddef> /* size_t */
> #include <new> /* Only for bad_alloc */
>
> template<typename T, std::size_t capacity>
> class StaticAllocator {
> public:
> typedef T value_type;
>
> protected:
>
> static T buf[capacity];
>
> public:
>
> T *allocate(std::size_t const n)
> {
> if (n > capacity)
> throw std::bad_alloc();
>
> return buf;
> }
>
> void deallocate(T *, std::size_t)
> {
> /* Do Nothing */
> }
> };
>
> template<typename T, std::size_t capacity>
> T StaticAllocator<T,capacity>::buf[capacity];

can't check but this is missing initializer?
just say buf and it will compile.

>
> using std::size_t;
>
> #include <vector>
> using std::vector;
>
> #include <iostream>
> using std::cout;
> using std::endl;
>
> auto main(void) -> int
> {
> vector< char, StaticAllocator<char, 4> > v;
>
> v.push_back('a');
> v.push_back('b');
> v.push_back('c');
> v.push_back('d');
>
> for (auto const &elem : v)
> cout << elem << endl;
>
> vector< char, StaticAllocator<char, 4> > v2;
>
> v2.push_back('x');
> v2.push_back('y');
> v2.push_back('z');
>
> for (auto const &elem : v2)
> cout << elem << endl;
>
> // Now try the first vector again
>
> for (auto const &elem : v)
> cout << elem << endl;
> }
>
>
What's the purpose of allocator when you can allocate only one
vector with it?

--
press any key to continue or any other to quit...
U ničemu ja ne uživam kao u svom statusu INVALIDA -- Zli Zec
Svi smo svedoci - oko 3 godine intenzivne propagande je dovoljno da jedan narod poludi -- Zli Zec
Na divljem zapadu i nije bilo tako puno nasilja, upravo zato jer su svi
bili naoruzani. -- Mladen Gogala

Paavo Helde

unread,
Jan 3, 2020, 2:33:08 PM1/3/20
to
On 3.01.2020 17:04, Frederick Gotham wrote:
>
> My GNU C++ compiler version 7.4.0 for Ubuntu won't compile the following code and I don't know why.
>
> If I remove the second template parameter, i.e. "size_t capacity", then it works fine.
>
> I wonder if another compiler will compile it?
>
> This code is for a new kind of allocator that uses global (i.e. static duration) memory.
>
> #include <cstddef> /* size_t */
> #include <new> /* Only for bad_alloc */
>
> template<typename T, std::size_t capacity>
> class StaticAllocator {


By deriving your allocator from std::allocator<T> it started to compile,
at least with my compiler and settings.

Theoretically this derivation should not be needed, but then it would
probably need to define some extra stuff. The allocator requirements
have been in great flux in the recent standards, I'm not sure what it is
missing exactly.

Frederick Gotham

unread,
Jan 4, 2020, 9:12:33 AM1/4/20
to
On Friday, January 3, 2020 at 7:33:08 PM UTC, Paavo Helde wrote:

> By deriving your allocator from std::allocator<T> it started to compile,
> at least with my compiler and settings.
>
> Theoretically this derivation should not be needed, but then it would
> probably need to define some extra stuff. The allocator requirements
> have been in great flux in the recent standards, I'm not sure what it is
> missing exactly.



I've tried this on three compilers: GNU, Microsoft, Clang

The original code which has two template parameters, "typename T, std::size_t capacity", only compiles on the Clang compiler.

The second version with only one template parameter, "typename T", compiles on all three compilers.

Since the second version works on all three compilers, I don't think that this problem is anything to do with how allocators are implemented in the respective standard libraries for these three compilers. Making the change from two parameters to one parameter shouldn't cause compilation to fail.

Here's the code for the second version which works on all three compilers (I've just commented out the 2nd parameter):

#include <cstddef> /* size_t */
#include <new> /* Only for bad_alloc */

std::size_t constexpr capacity = 4; /* This is instead of a template parameter */

template<typename T /*, std::size_t capacity*/ >
class StaticAllocator {
public:
typedef T value_type;

protected:

static T buf[capacity];

public:

T *allocate(std::size_t const n)
{
if (n > capacity)
throw std::bad_alloc();

return buf;
}

void deallocate(T *, std::size_t)
{
/* Do Nothing */
}
};

template<typename T /*, std::size_t capacity*/ >
T StaticAllocator<T /*,capacity*/ >::buf[capacity];

using std::size_t;

#include <vector>
using std::vector;

#include <iostream>
using std::cout;
using std::endl;

auto main(void) -> int
{
vector< char, StaticAllocator<char /*, 4*/ > > v;

v.push_back('a');
v.push_back('b');
v.push_back('c');
v.push_back('d');

for (auto const &elem : v)
cout << elem << endl;

vector< char, StaticAllocator<char /*, 4 */> > v2;

Bo Persson

unread,
Jan 4, 2020, 9:53:31 AM1/4/20
to
Seems like the culprit is the rebind member template from the allocator
requirements. MSVC uses that to make sure that the allocator used for
vector<T> really allocates T's:

using _Rebind_alloc_t =
typename allocator_traits<_Alloc>::template rebind_alloc<_Value_type>;


The allocator table says:

A::template rebind<U>::other (optional)[1]

with the very important note:

"Notes:

rebind is only optional (provided by std::allocator_traits) if this
allocator is a template of the form SomeAllocator<T, Args>, where Args
is zero or more additional template type parameters."

https://en.cppreference.com/w/cpp/named_req/Allocator#cite_note-1


As your second template parameter is a non-type template parameter (the
value 4), it doesn't *fully* comply with these requirements and so a
compiler doesn't have to accept it.


Apparently, some compilers might work if the allocator is *almost*
correct, but they don't have to.


Bo Persson



Frederick Gotham

unread,
Jan 4, 2020, 5:34:58 PM1/4/20
to
Bo wrote:

> rebind is only optional (provided by std::allocator_traits) if this
> allocator is a template of the form SomeAllocator<T, Args>, where Args
> is zero or more additional template type parameters."


Well spotted. Here's my workaround:


#include <cstddef> /* size_t */
#include <new> /* Only for bad_alloc */

template <std::size_t capacity>
class Outer {

template<typename T>
class StaticAllocator {
public:
typedef T value_type;

protected:

static T buf[capacity];

public:

T *allocate(std::size_t const n)
{
if (n > capacity)
throw std::bad_alloc();

return buf;
}

void deallocate(T *, std::size_t)
{
/* Do Nothing */
}
};

};

template<std::size_t capacity>
template<typename T>
T Outer<capacity>::StaticAllocator<T>::buf[capacity];

using std::size_t;

#include <vector>
using std::vector;

#include <iostream>
using std::cout;
using std::endl;

auto main(void) -> int
{
vector< char, Outer<4>::StaticAllocator<char> > v;

v.push_back('a');
v.push_back('b');
v.push_back('c');
v.push_back('d');

for (auto const &elem : v)
cout << elem << endl;

vector< char, Outer<4>::StaticAllocator<char> > v2;

v2.push_back('x');
v2.push_back('y');
v2.push_back('z');

for (auto const &elem : v2)
cout << elem << endl;

// Now try the first vector again

for (auto const &elem : v)
cout << elem << endl;
}


Now I can get back to testing my new allocator.

Manfred

unread,
Jan 5, 2020, 4:31:20 PM1/5/20
to
The following satisfies the rebind requirement, although I do not know
how this may play in a more elaborate context:

template<typename T, std::size_t capacity>
class StaticAllocator {
public:
typedef T value_type;

protected:

static T buf[capacity];

public:

template<typename U>
struct rebind
{
typedef StaticAllocator<U, capacity> other;
};

Frederick Gotham

unread,
Jan 6, 2020, 5:12:41 AM1/6/20
to
Taking in Bo and Manfred's changes, here's my latest rendition:

#include <cstddef> /* size_t */
#include <new> /* Only for bad_alloc */

static int const thisfile = 0; /* This serves the same purpose as __FILE__ */

template<typename T, std::size_t t_capacity, std::size_t t_counter, int const *t_file>
class StaticAllocator {
protected:

static T buf[t_capacity];

public:

typedef T value_type;

template<typename U>
struct rebind {
typedef StaticAllocator<U, t_capacity, t_counter, t_file> other;
};

T *allocate(std::size_t const n)
{
if (n > t_capacity)
throw std::bad_alloc();

return buf;
}

void deallocate(T *, std::size_t)
{
/* Do Nothing */
}
};

template<typename T, std::size_t t_capacity, std::size_t t_counter, int const *t_file>
T StaticAllocator<T, t_capacity, t_counter, t_file>::buf[t_capacity];

using std::size_t;

#include <vector>
using std::vector;

#include <iostream>
using std::cout;
using std::endl;

auto main(void) -> int
{
vector< char, StaticAllocator< char, 4, __COUNTER__, &thisfile > > v;

v.push_back('a');
v.push_back('b');
v.push_back('c');
v.push_back('d');

for (auto const &elem : v)
cout << elem << endl;

vector< char, StaticAllocator< char, 4, __COUNTER__, &thisfile > > v2;

v2.push_back('x');
v2.push_back('y');
v2.push_back('z');

for (auto const &elem : v2)
cout << elem << endl;

// Now try the first vector again

for (auto const &elem : v)
cout << elem << endl;
}


This compiles and works as intended on GNU and Clang, however it fails to compile on Microsoft with the following error:

template parameter 't_file': 'thisfile':
an expression involving objects with internal linkage cannot
be used as a non-type argument

Anyone got any more ideas? I'm hoping to submit this to Boost soon.

Frederick Gotham

unread,
Jan 7, 2020, 2:52:16 AM1/7/20
to
I have cleaned it up again a little. This time I'm using a default template parameter.

#include <cstddef> /* size_t */
#include <new> /* Only for bad_alloc */

static int this_translation_unit; /* This serves the same purpose as __FILE__ */

template<typename T, std::size_t t_capacity, std::size_t t_counter, int *t_file = &this_translation_unit>
class StaticAllocator {
protected:

static T buf[t_capacity];

public:

typedef T value_type;

template<typename U>
struct rebind {
typedef StaticAllocator<U, t_capacity, t_counter, t_file> other;
};

T *allocate(std::size_t const n)
{
if (n > t_capacity)
throw std::bad_alloc();

return buf;
}

void deallocate(T *, std::size_t)
{
/* Do Nothing */
}
};

template<typename T, std::size_t t_capacity, std::size_t t_counter, int *t_file>
T StaticAllocator<T, t_capacity, t_counter, t_file>::buf[t_capacity];

using std::size_t;

#include <vector>
using std::vector;

#include <iostream>
using std::cout;
using std::endl;

auto main(void) -> int
{
vector< char, StaticAllocator< char, 4, __COUNTER__ > > v;

v.push_back('a');
v.push_back('b');
v.push_back('c');
v.push_back('d');

for (auto const &elem : v)
cout << elem << endl;

vector< char, StaticAllocator< char, 4, __COUNTER__ > > v2;

v2.push_back('x');
v2.push_back('y');
v2.push_back('z');

for (auto const &elem : v2)
cout << elem << endl;

// Now try the first vector again

for (auto const &elem : v)
cout << elem << endl;
}

I'm submitting this to the Boost development mailing list today.

Ian Collins

unread,
Jan 7, 2020, 3:15:43 AM1/7/20
to
On 04/01/2020 04:04, Frederick Gotham wrote:

>
> auto main(void) -> int

What kind of an abomination is this?

--
Ian.

Frederick Gotham

unread,
Jan 7, 2020, 4:01:35 AM1/7/20
to
On Tuesday, January 7, 2020 at 8:15:43 AM UTC, Ian Collins wrote:

> > auto main(void) -> int
>
> What kind of an abomination is this?


It fails to compile on older C++ compilers, before C++11.

Melzzzzz

unread,
Jan 7, 2020, 4:20:15 AM1/7/20
to
On 2020-01-03, Frederick Gotham <cauldwel...@gmail.com> wrote:
>
> My GNU C++ compiler version 7.4.0 for Ubuntu won't compile the following code and I don't know why.

Because allocator has only one template parameter and that's expected.
As I see it.

Melzzzzz

unread,
Jan 7, 2020, 4:20:58 AM1/7/20
to
People write some other language that is not C++ ;)

Melzzzzz

unread,
Jan 7, 2020, 4:35:16 AM1/7/20
to
On 2020-01-07, Melzzzzz <Melz...@zzzzz.com> wrote:
> On 2020-01-03, Frederick Gotham <cauldwel...@gmail.com> wrote:
>>
>> My GNU C++ compiler version 7.4.0 for Ubuntu won't compile the following code and I don't know why.
>
> Because allocator has only one template parameter and that's expected.
> As I see it.
>
>
And you need rebind if allocator has additional arguments...

Bonita Montero

unread,
Jan 7, 2020, 4:37:05 AM1/7/20
to
Forget writing an allocator that doesn't have full heap-semantics.
The C++-containers often rebind the allocator-type for orther
allocators; f.e. an unordered_map might do a rebind for the
bucket-nodes (it gets only a allocator<pair<const Key, T>,
which isn't sufficient for everything a unordered_map needs).

Bonita Montero

unread,
Jan 7, 2020, 4:42:44 AM1/7/20
to
I tried to write my own allocator that relies on VirtualAlloc() or
mmap(). But it doesn't work for the above reason; i.e. the allocator
might get rebound and the new allocator might be used for tiny amounts
of memory, rounded up to a page-size.

#ifdef _MSC_VER
#include <Windows.h>
#elif __unix__
#include <sys/mman.h>
#endif
#include <cstddef>
#include <exception>
#include <cassert>
#include <new>

#include <iostream>

template<class T>
class virtual_allocator
{
public:
typedef T value_type;
#if __cplusplus < 201703L
typedef T *pointer;
typedef const T *const_pointer;
typedef T &reference;
typedef const T &const_reference;
#endif
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
#if __cplusplus < 201703L
template<typename U>
struct rebind
{
typedef virtual_allocator<U> other;
};
#endif

explicit virtual_allocator() = default;
explicit virtual_allocator( virtual_allocator const
&other ) = default;
template<typename U>
virtual_allocator( virtual_allocator<U> const
&other );
#if __cplusplus < 201703L
static pointer address( reference value );
static const_pointer address( const_reference value );
static size_type max_size() throw();
#endif
#if __cplusplus >= 201703L
T *allocate( size_type n, void *hint = nullptr );
void deallocate( T *p, size_type num = 1 );
#else
pointer allocate( size_type n, void *hint = nullptr );
void deallocate( pointer p, size_type num = 1 );
#endif
#if __cplusplus < 201703L
static void construct( pointer p, const T&value );
template<typename U>
static void destroy( U *p );
#endif
};

template<typename T>
template<typename U>
inline
virtual_allocator<T>::virtual_allocator( virtual_allocator<U> const
&other ) :
virtual_allocator()
{
}

#if __cplusplus < 201703L
template<typename T>
inline
typename virtual_allocator<T>::pointer virtual_allocator<T>::address(
reference value )
{
return &value;
}

template<typename T>
inline
typename virtual_allocator<T>::const_pointer
virtual_allocator<T>::address( const_reference value )
{
return &value;
}

template<typename T>
inline
typename virtual_allocator<T>::size_type
virtual_allocator<T>::max_size() throw()
{
return (size_t)(ptrdiff_t)-1 / sizeof(T);
}
#endif

template<typename T>
#if __cplusplus >= 201703L
T *virtual_allocator<T>::allocate( size_type n, void *hint )
#else
typename virtual_allocator<T>::pointer virtual_allocator<T>::allocate(
size_type n, void *hint )
#endif
{
std::cout << "allocate" << n << std::endl;
#if defined(_MSC_VER)
T *p = (T *)VirtualAlloc( hint, n * sizeof(T), MEM_RESERVE |
MEM_COMMIT, PAGE_READWRITE );
if( !p )
throw std::bad_alloc();
return p;
#elif __unix__
void *p = mmap( hint, n * sizeof(T), PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0 );
if( p == MAP_FAILED )
throw std::bad_alloc();
return (pointer)p;
#else
#error no implementation for your OS
#endif
}

template<typename T>
#if __cplusplus >= 201703L
inline
void virtual_allocator<T>::deallocate( T *p, size_type n )
#else
inline
void virtual_allocator<T>::deallocate( pointer p, size_type n )
#endif
{
std::cout << "dellocate " << n << std::endl;
#if defined(_MSC_VER)
BOOL ret = VirtualFree( p, 0, MEM_RELEASE );
assert(ret);
#elif __unix__
int ret = munmap( p, n * sizeof(T) );
assert(ret == 0);
#else
#error no implementation for your OS
#endif
}

#if __cplusplus < 201703L
template<typename T>
inline
void virtual_allocator<T>::construct( pointer p, const T&value )
{
new( (void*)p ) T( value );
}

template<typename T>
template<typename U>
inline
void virtual_allocator<T>::destroy( U *p )
{
p->~T();
}
#endif

Melzzzzz

unread,
Jan 7, 2020, 4:43:10 AM1/7/20
to
On 2020-01-07, Melzzzzz <Melz...@zzzzz.com> wrote:
> On 2020-01-07, Melzzzzz <Melz...@zzzzz.com> wrote:
>> On 2020-01-03, Frederick Gotham <cauldwel...@gmail.com> wrote:
>>>
>>> My GNU C++ compiler version 7.4.0 for Ubuntu won't compile the following code and I don't know why.
>>
>> Because allocator has only one template parameter and that's expected.
>> As I see it.
>>
>>
> And you need rebind if allocator has additional arguments...
>
add this:
template <class U> struct rebind{ typedef StaticAllocator<U,capacity> other; };

Bonita Montero

unread,
Jan 7, 2020, 4:47:08 AM1/7/20
to
>>>> My GNU C++ compiler version 7.4.0 for Ubuntu won't compile the following code and I don't know why.

>>> Because allocator has only one template parameter and that's expected.
>>> As I see it.

>> And you need rebind if allocator has additional arguments...

> add this:
> template <class U> struct rebind{ typedef StaticAllocator<U,capacity> other; };

The rebind-member of an allocator is deprecated in C++17 and removed in
C++20. You would have to specialize std::allocator_traits<youralloc> for
your own allocator. I don't like this because having a own rebind-member
results in writing less code.

Bonita Montero

unread,
Jan 7, 2020, 4:59:24 AM1/7/20
to
> The rebind-member of an allocator is deprecated in C++17 and removed in
> C++20. You would have to specialize std::allocator_traits<youralloc> for
> your own allocator. I don't like this because having a own rebind-member
> results in writing less code.

Hm, how do I specialize std::allocator_traits<Alloc> for a special
allocator? Can I do it this way:

template<>
template<typename T>
struct std::allocator_traits<virtual_allocator<T>>
{
};

With this I get a single error vom MSVC and myriads of errors from gcc.

Melzzzzz

unread,
Jan 7, 2020, 5:02:39 AM1/7/20
to
Hassle just to have additional parameter in allocator :(

Melzzzzz

unread,
Jan 7, 2020, 5:16:03 AM1/7/20
to
On 2020-01-07, Bonita Montero <Bonita....@gmail.com> wrote:
Sorry, I haven't messed with templates long time, except in simple
cases.
I have to figure this out myself ;)

Bonita Montero

unread,
Jan 7, 2020, 5:21:24 AM1/7/20
to
>> Hm, how do I specialize std::allocator_traits<Alloc> for a special
>> allocator? Can I do it this way:
>> template<>
>> template<typename T>
>> struct std::allocator_traits<virtual_allocator<T>>
>> {
>> };
>> With this I get a single error vom MSVC and myriads of errors from gcc.

> Sorry, I haven't messed with templates long time, except in simple
> cases.
> I have to figure this out myself ;)

Here's the reduced code that produces the same error with MSVC but
it compiles with g++:

template<typename T>
struct My
{
};

template<typename T>
struct Lib
{
};

template<>
template<typename T>
struct Lib<My<T>>
{
};

int main()
{
Lib<My<int>> lmi;
}

Melzzzzz

unread,
Jan 7, 2020, 5:25:17 AM1/7/20
to
On 2020-01-07, Bonita Montero <Bonita....@gmail.com> wrote:
>>> Hm, how do I specialize std::allocator_traits<Alloc> for a special
>>> allocator? Can I do it this way:
>>> template<>
>>> template<typename T>
>>> struct std::allocator_traits<virtual_allocator<T>>
>>> {
>>> };
>>> With this I get a single error vom MSVC and myriads of errors from gcc.
>
>> Sorry, I haven't messed with templates long time, except in simple
>> cases.
>> I have to figure this out myself ;)
>
> Here's the reduced code that produces the same error with MSVC but
> it compiles with g++:

Long time ago someone said: templates, write once, get compile errors
everywhere ;)

>
> template<typename T>
> struct My
> {
> };
>
> template<typename T>
> struct Lib
> {
> };
>
> template<>
> template<typename T>
> struct Lib<My<T>>
> {
> };
>
> int main()
> {
> Lib<My<int>> lmi;
> }


Bo Persson

unread,
Jan 7, 2020, 9:27:39 AM1/7/20
to
It is only removed from the std::allocator (where it is no longer needed
now that we also have std::allocator_traits), but it is still an
optional part of the allocator interface.


https://en.cppreference.com/w/cpp/named_req/Allocator



Bo Persson

Ian Collins

unread,
Jan 7, 2020, 1:31:39 PM1/7/20
to
It should fail to compile with compilers that enforce good taste.

--
Ian.

Bonita Montero

unread,
Jan 7, 2020, 1:51:02 PM1/7/20
to
>> It fails to compile on older C++ compilers, before C++11

> It should fail to compile with compilers that enforce good taste.

auto isn't good taste except when necessary.

bol...@nowhere.org

unread,
Jan 8, 2020, 5:12:16 AM1/8/20
to
Its for developers who like to show off: "Look at me, I'm using unnecessarily
complex syntax for no good reason - I must truly be l33t!"

Anyone who wrote that sort of crap in an interview test for me would have their
CV shown the bin the minute they left.

Keith Thompson

unread,
Jan 8, 2020, 12:22:20 PM1/8/20
to
There are some advantages to trailing return types (introduced in
C++11) particularly for function templates where the return type
depends on the argument types.

If C++ were being designed from scratch today, I suspect that they
would be the only syntax accepted, with the leading "auto" omitted.
Other than historical baggage, there's no good reason to have two
different syntax for return types.

Some have argued that we should use trailing return types
consistently in new code. Others would argue that we shouldn't
use them in cases where they offer no specific advantages, simply
because they're unfamiliar. I tend to fall into the latter camp,
but I can imagine changing my mind eventually.

--
Keith Thompson (The_Other_Keith) Keith.S.T...@gmail.com
[Note updated email address]
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */

Melzzzzz

unread,
Jan 8, 2020, 12:44:56 PM1/8/20
to
On 2020-01-08, Keith Thompson <Keith.S.T...@gmail.com> wrote:
> Ian Collins <ian-...@hotmail.com> writes:
>> On 04/01/2020 04:04, Frederick Gotham wrote:
>>> auto main(void) -> int
>>
>> What kind of an abomination is this?
>
> There are some advantages to trailing return types (introduced in
> C++11) particularly for function templates where the return type
> depends on the argument types.
>
> If C++ were being designed from scratch today, I suspect that they
> would be the only syntax accepted, with the leading "auto" omitted.

Or fun fn func etc...

Alf P. Steinbach

unread,
Jan 8, 2020, 5:01:04 PM1/8/20
to
On 08.01.2020 18:22, Keith Thompson wrote:
> Ian Collins <ian-...@hotmail.com> writes:
>> On 04/01/2020 04:04, Frederick Gotham wrote:
>>> auto main(void) -> int
>>
>> What kind of an abomination is this?
>
> There are some advantages to trailing return types (introduced in
> C++11) particularly for function templates where the return type
> depends on the argument types.
>
> If C++ were being designed from scratch today, I suspect that they
> would be the only syntax accepted, with the leading "auto" omitted.

"Implicit auto" for the win!

Then, in an even later version of C++ that will be deprecated and one
will be required to spell out Unicode `ℱ` (capital script F).


> Other than historical baggage, there's no good reason to have two
> different syntax for return types.
>
> Some have argued that we should use trailing return types
> consistently in new code. Others would argue that we shouldn't
> use them in cases where they offer no specific advantages, simply
> because they're unfamiliar. I tend to fall into the latter camp,
> but I can imagine changing my mind eventually.
>

- Alf

Tim Rentsch

unread,
Jan 10, 2020, 9:49:01 AM1/10/20
to
As abominations go, it's one of the best.

Tim Rentsch

unread,
Jan 10, 2020, 10:06:23 AM1/10/20
to
So, not on any currently conforming C++ compiler, you mean?

Frederick Gotham

unread,
Jan 14, 2020, 5:25:51 AM1/14/20
to
On Friday, January 10, 2020 at 3:06:23 PM UTC, Tim Rentsch wrote:

> > It should fail to compile with compilers that enforce good taste.
>
> So, not on any currently conforming C++ compiler, you mean?


I, too, tried logic on this argument here on this newsgroup. I found that logic failed. I might try rationale next.
0 new messages