简体   繁体   中英

C++ type alias and forward declaration with default template parameter

I wanna use span class implementation from 3rd party header-only library, but use different namespace for it. What I pretty much did is create new span.hpp proxy header which includes library and introduces it to new namespace.

Now, when trying to include that proxy header, my whole translation unit compilation breaks as if it was syntatically incorrect (lots and lots of random errors)

(EDIT: I found the error in question and pasted it at the very bottom):

namespace new_namespace
{

   template <std::size_t Value = ::old_namespace::dynamic_extent>
   class span;

   template <std::size_t Value>
   using span = ::old_namespace::span<Value>;

}

After simplyfying code a little bit it works just fine:

namespace new_namespace
{

   template <std::size_t Value = ::old_namespace::dynamic_extent>
   using span = ::old_namespace::span<Value>;
}

My question is - say I really, really wanna keep forward declaration with default template parameter and type alias separate. How do I achieve this in this scenario?

Edit:

The error in question is:

/span.hpp:12:46: error: conflicting declaration of template 'template<long unsigned int Value> using span = old_namespace::span<T>'

 using span = ::old_namespace::span<Value>;
                                          ^
/span.hpp:9:7: note: previous declaration 'template<long unsigned int Value> class new_namespace::span'

 class span;

So both are treated as declarations? What is going on here exactly and how are they conflicting?

One more thing, the definition of old_namespace::span provides a default value for template parameter Value in the form of:

namespace old_namespace
{

template <typename Value = dynamic_extent> // Default parameter in forward declaration
class span;

template <typename Value> // No default parameter here
class span
{
   ...
}

}

Why isn't using alias looking for default template parameters from original class? If I try to omit default parameter eg simply writing:

namespace new_namespace
{
   template <std::size_t Value> // no default parameter provided
   using span = ::old_namespace::span<Value>;
}

I get error when trying to instantiate span without any template parameters

Thanks for help in advance. :)

Cheers

This cannot work the way you want it to (with a forward declaration) according to the spec. A forward declaration cannot be defined later by using . From the C++11 spec on using-declaration :

Since a using-declaration is a declaration, the restrictions on declarations of the same name in the same declarative region (3.3) also apply to using-declarations . -- [namespace.udecl] §7.3.3 ¶13

I believe the problem to be that a class forward declaration and a using-declaration are... rather obviously, both declarations .

// Declares span as a template class.
template <std::size_t Value = ::old_namespace::dynamic_extent>
class span;

// Attempts to redeclare span as something else -- this is invalid.
template <std::size_t Value>
using span = ::old_namespace::span<Value>;

In the example you've given where this works with only class , you do not have two declarations -- you have a forward declaration and a definition (which implies declaration if not already declared ):

// Forward declaration.
template <typename Value = dynamic_extent>
class span;

// Definition, which agrees with the forward declaration -- no error.
template <typename Value>
class span
{
   ...
}

The crux of the issue is rather straightforward: you can't declare the same name to mean two different things:

Given a set of declarations in a single declarative region, each of which specifies the same unqualified name,

  • they shall all refer to the same entity... -- [basic.scope.declarative] §3.3.1 ¶4

When you try to use class and using together in this way, they do not refer to the same entity. Therefore, this is not allowed.


A possible solution this problem is to use template parameter packs in your aliases:

template <std::size_t... T>
using span = ::old_namespace::span<T...>;

Now span<> is an alias for ::old_namespace::span<> , and any defaults will be used as appropriate.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM