1

I am writing stratum streambuf deriving from std::basic_streambuf:

/// Basic Socket Buffer
template<
        typename CharT_,
        typename Traits_ = std::char_traits< CharT_ > >
class BasicSocketBuffer //BasicSocketStreamBuffer
        : public std::basic_streambuf< CharT_, Traits_ >
{
...
    virtual int_type
    overflow(int_type __c = traits_type::eof());
...

Errors:

error: 'int_type' does not name a type
    virtual int_type
             ^~~~~~~~
note: (perhaps 'typename std::basic_streambuf<_CharT, _Traits>::int_type' was intended)

Ha-ha. Compiler knows what I want, but won't do. Why?

Here are first lines of parent std class:

template<typename _CharT, typename _Traits>
class basic_streambuf
{
public:
    //@{
    /**
     *  These are standard types.  They permit a standardized way of
     *  referring to names of (or names dependent on) the template
     *  parameters, which are specific to the implementation.
    */
    typedef _CharT char_type;
    typedef _Traits traits_type;
    typedef typename traits_type::int_type int_type;
    typedef typename traits_type::pos_type pos_type;
    typedef typename traits_type::off_type off_type;
...

Workaround

Almost redeclare all used types once more in derived class;

class Derived : class Parent {
  using Parent::int_type;  // for non-templated
  using typename Parent::char_type;
...

Do you know better way? C++11,14 are welcome.

Mike Kinghan
  • 55,740
  • 12
  • 153
  • 182
kyb
  • 7,233
  • 5
  • 52
  • 105
  • The linked question is about having to write `this->name` vs `name`, but all the same stuff applies to accessing typedefs. – Barry Jun 20 '17 at 13:51
  • 1
    But it is a different question: even if the same stuff applies, the solution is not `this->int_type`, but `typename base::int_type`. – Walter Jun 20 '17 at 13:57
  • 1
    Well, almost the same stuff, but you can't write `this->int_type`. – MSalters Jun 20 '17 at 13:57
  • 1
    @Barry I suggest you find a better dupe than that. – Walter Jun 20 '17 at 13:58
  • I would not say this is duplicate, but say *"Problem is similar to LINK. Solution could be found there."* – kyb Jun 20 '17 at 13:58
  • Seems my "workaround" is the only way..? – kyb Jun 20 '17 at 14:03
  • @Walter If you want to find a better dupe, go for it - I think the linked answer does a good job of explaining the issue and why you need to qualify name access to dependent bases, but hey - it doesn't *literally address this exact question* so I guess it sucks (shrug). – Barry Jun 20 '17 at 14:45
  • @Barry, thank you for that link. But as for me this Q is not a duplicate, and I'd better like to see your link in an answer. Or let me post a good answer with your link. Please unmark *dupe* flag. – kyb Jun 20 '17 at 15:14
  • Please do not add answer to the question body. – bolov Jun 21 '17 at 07:58
  • 1
    @Barry voted for repopen. Please either edit the duped question to incorporate "find base class members" (perhaps mention typedefs). Or choose another duped question. Reasing for dupe-closing is twofold: Prevent cluttering the SO-database, but also help users find (more) valuable solutions to their problems. So a duped question needs to be findable on search engines. – Johannes Schaub - litb Jun 21 '17 at 08:48
  • @Barry even more relevant: This answer *already* shows how to apply qualified name lookup to find base class members and calls it a "workaround" and asks for better solutions. I don't see how telling him "use qualified lookup" solves that inquiry (BTW he wants to be able to still say "int_type" apparently, so simply pointing to that duped question, even if it's edited, isn't sufficient IMO). – Johannes Schaub - litb Jun 21 '17 at 08:50
  • @bolov, I have added answer to question because. answering was disallowed. Now I can post answer. – kyb Jun 21 '17 at 11:54
  • @JohannesSchaub-litb, thank you for support. – kyb Jun 21 '17 at 11:55

2 Answers2

1

Ha-ha. Compiler knows what I want, but won't do. Why?

The C++ standard says you must use typename there for the code to be valid, because name lookup in class templates does not look in dependent bases. See https://gcc.gnu.org/wiki/VerboseDiagnostics#dependent_base and the explanations it links to.

Do you know better way?

That is the correct way.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
-1

The only way to inherit types from class template is to redefine them once more. In my case the simplest way is copy-paste from Parent class:

/// Basic Socket Buffer
template<
        typename CharT_,
        typename Traits_ = std::char_traits< CharT_ > >
class BasicSocketBuffer //BasicSocketStreamBuffer
        : public std::basic_streambuf< CharT_, Traits_ >
{
...
public:
    //@{
    /**
     *  These are standard types.  They permit a standardized way of
     *  referring to names of (or names dependent on) the template
     *  parameters, which are specific to the implementation.
    */
    typedef _CharT char_type;
    typedef _Traits traits_type;
    typedef typename traits_type::int_type int_type;
    typedef typename traits_type::pos_type pos_type;
    typedef typename traits_type::off_type off_type;
...

This way is C++98 compatible.

Other modern and nicer way is to declare SuperType and reusing its internal types:

/// Basic Socket Buffer
template<
        typename CharT_,
        typename Traits_ = std::char_traits< CharT_ > >
class BasicSocketBuffer //BasicSocketStreamBuffer
        : public std::basic_streambuf< CharT_, Traits_ >
{
...
public:
    using SuperBuffer = std::basic_streambuf< CharT_, Traits_ >;
    //@{
    /**
     *  These are standard types.  They permit a standardized way of
     *  referring to names of (or names dependent on) the template
     *  parameters, which are specific to the implementation.
    */
    using typename SuperBuffer::char_type;
    using typename SuperBuffer::traits_type;
    using typename SuperBuffer::int_type;
    using typename SuperBuffer::pos_type;
    using typename SuperBuffer::off_type;
...

Inner types of SuperBuffer (SuperBuffer::InnerX) could be used directly without =, but SuperBuffer::InnerX::InnerY must be reused with = because InnerX is not a base type for BasicSocketBuffer.
typename is required for class templates.

kyb
  • 7,233
  • 5
  • 52
  • 105