SFINAE revisited

Discussion in 'C++' started by James Kanze, Jul 15, 2008.

  1. James Kanze

    James Kanze Guest

    Just ran into an interesting question concerning SFINAE. Given
    the following code:

    #include <iostream>
    #include <typeinfo>

    template< typename T >
    class P
    {
    public:
    P( T* ) { std::cout << "In P: normal ctor" << std::endl ; }
    template< typename U >
    P( U* ) { std::cout << "In P: template ctor (U = "
    << typeid( U ).name() << ')' << std::endl ; }
    } ;

    class B
    {
    public:
    virtual ~B() {}
    } ;

    int
    main()
    {
    class D : public B {} ;
    P< B > p( new D ) ;
    return 0 ;
    }

    Should this compile, and if so, what should the program output?
    I've got three different compilers at hand: one fails to
    compile, one outputs "In P: normal ctor", and one outputs "In P:
    template ctor (U = ...)", where the ... is the mangled name of
    D. (My own feeling is that it shouldn't compile. But I'm not
    all that clear about template argument deduction, and at what
    level SFINAE kicks in.)

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Jul 15, 2008
    #1
    1. Advertising

  2. James Kanze

    joseph cook Guest

    On Jul 15, 12:22 pm, James Kanze <> wrote:
    > Just ran into an interesting question concerning SFINAE.  Given
    > the following code:
    >
    >     #include <iostream>
    >     #include <typeinfo>
    >
    >     template< typename T >
    >     class P
    >     {
    >     public:
    >         P( T* ) { std::cout << "In P: normal ctor" << std::endl ; }
    >         template< typename U >
    >         P( U* ) { std::cout << "In P: template ctor (U = "
    >                     << typeid( U ).name() << ')' << std::endl ; }
    >     } ;
    >
    >     class B
    >     {
    >     public:
    >         virtual             ~B() {}
    >     } ;
    >
    >     int
    >     main()
    >     {
    >         class D : public B {} ;
    >         P< B > p( new D ) ;
    >         return 0 ;
    >     }
    >
    > Should this compile, and if so, what should the program output?
    > I've got three different compilers at hand: one fails to
    > compile, one outputs "In P: normal ctor", and one outputs "In P:
    > template ctor (U = ...)", where the ... is the mangled name of
    > D.  (My own feeling is that it shouldn't compile.  But I'm not
    > all that clear about template argument deduction, and at what
    > level SFINAE kicks in.)



    Is this any different than having the same set-up with functions
    instead of constructors?

    template<typename T>
    class Foo
    {
    public:
    void goo(T* a) { std::cout << "In Foo: normal fn" << std::endl ;}
    template<typename U>
    void goo(U* a) { std::cout <<"Int Foo: templated fn"<<std::endl;
    };

    class B { public: virtual ~B(){} };
    class D : public B{};

    int main()
    {
    Foo<B> foo;
    foo.goo(new D);
    }

    I would think this last line reliably (and rightfully) always chooses
    the templated function, but if replaced by "new B" would pick the
    "normal fn".

    I don't see why Constructors should behave differently (I'd bd curious
    if your "three compilers" behave differently in my example.

    Joe Cook
     
    joseph cook, Jul 15, 2008
    #2
    1. Advertising

  3. James Kanze wrote:
    > Just ran into an interesting question concerning SFINAE. Given
    > the following code:
    >
    > #include <iostream>
    > #include <typeinfo>
    >
    > template< typename T >
    > class P
    > {
    > public:
    > P( T* ) { std::cout << "In P: normal ctor" << std::endl ; }
    > template< typename U >
    > P( U* ) { std::cout << "In P: template ctor (U = "
    > << typeid( U ).name() << ')' << std::endl ; }
    > } ;
    >
    > class B
    > {
    > public:
    > virtual ~B() {}
    > } ;
    >
    > int
    > main()
    > {
    > class D : public B {} ;
    > P< B > p( new D ) ;
    > return 0 ;
    > }
    >
    > Should this compile, and if so, what should the program output?
    > I've got three different compilers at hand: one fails to
    > compile, one outputs "In P: normal ctor", and one outputs "In P:
    > template ctor (U = ...)", where the ... is the mangled name of
    > D. (My own feeling is that it shouldn't compile. But I'm not
    > all that clear about template argument deduction, and at what
    > level SFINAE kicks in.)


    First a question: was it intentional that D is a local class? That's
    the only reason I see for it not to compile (modulo N2580 :)).

    --
    Gennaro Prota | <https://sourceforge.net/projects/breeze/>
    Do you need expertise in C++? I'm available.
     
    Gennaro Prota, Jul 15, 2008
    #3
  4. James Kanze

    James Kanze Guest

    On Jul 15, 7:44 pm, joseph cook <> wrote:
    > On Jul 15, 12:22 pm, James Kanze <> wrote:
    > > Just ran into an interesting question concerning SFINAE.
    > > Given the following code:


    > > #include <iostream>
    > > #include <typeinfo>


    > > template< typename T >
    > > class P
    > > {
    > > public:
    > > P( T* ) { std::cout << "In P: normal ctor" << std::endl ; }
    > > template< typename U >
    > > P( U* ) { std::cout << "In P: template ctor (U = "
    > > << typeid( U ).name() << ')' << std::endl ; }
    > > } ;


    > > class B
    > > {
    > > public:
    > > virtual ~B() {}
    > > } ;


    > > int
    > > main()
    > > {
    > > class D : public B {} ;
    > > P< B > p( new D ) ;
    > > return 0 ;
    > > }


    > > Should this compile, and if so, what should the program output?
    > > I've got three different compilers at hand: one fails to
    > > compile, one outputs "In P: normal ctor", and one outputs "In P:
    > > template ctor (U = ...)", where the ... is the mangled name of
    > > D. (My own feeling is that it shouldn't compile. But I'm not
    > > all that clear about template argument deduction, and at what
    > > level SFINAE kicks in.)


    > Is this any different than having the same set-up with functions
    > instead of constructors?


    Probably not. I just happened to run into it with constructors.

    > template<typename T>
    > class Foo
    > {
    > public:
    > void goo(T* a) { std::cout << "In Foo: normal fn" << std::endl ;}
    > template<typename U>
    > void goo(U* a) { std::cout <<"Int Foo: templated fn"<<std::endl;
    > };


    > class B { public: virtual ~B(){} };
    > class D : public B{};


    > int main()
    > {
    > Foo<B> foo;
    > foo.goo(new D);
    > }


    > I would think this last line reliably (and rightfully) always
    > chooses the templated function, but if replaced by "new B"
    > would pick the "normal fn".


    Certainly, but you've changed one very important part; in my
    code, the derived class is local, which means that it's illegal
    to instantiate a template over it.

    > I don't see why Constructors should behave differently (I'd bd
    > curious if your "three compilers" behave differently in my
    > example.


    I doubt they do, but your example has nothing to do with my
    question.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Jul 15, 2008
    #4
  5. James Kanze

    James Kanze Guest

    On Jul 15, 7:54 pm, Gennaro Prota <> wrote:
    > James Kanze wrote:
    > > Just ran into an interesting question concerning SFINAE. Given
    > > the following code:


    > > #include <iostream>
    > > #include <typeinfo>


    > > template< typename T >
    > > class P
    > > {
    > > public:
    > > P( T* ) { std::cout << "In P: normal ctor" << std::endl ; }
    > > template< typename U >
    > > P( U* ) { std::cout << "In P: template ctor (U = "
    > > << typeid( U ).name() << ')' << std::endl ; }
    > > } ;


    > > class B
    > > {
    > > public:
    > > virtual ~B() {}
    > > } ;


    > > int
    > > main()
    > > {
    > > class D : public B {} ;
    > > P< B > p( new D ) ;
    > > return 0 ;
    > > }


    > > Should this compile, and if so, what should the program output?
    > > I've got three different compilers at hand: one fails to
    > > compile, one outputs "In P: normal ctor", and one outputs "In P:
    > > template ctor (U = ...)", where the ... is the mangled name of
    > > D. (My own feeling is that it shouldn't compile. But I'm not
    > > all that clear about template argument deduction, and at what
    > > level SFINAE kicks in.)


    > First a question: was it intentional that D is a local class?


    Obviously. Otherwise, there's no reason for it not to compile,
    and systematically chose the template constructor.

    > That's the only reason I see for it not to compile (modulo
    > N2580 :)).


    I'll have a glance at the paper you cite, but the heart of the
    question, of course, is what happens when template argument
    deduction comes up with a local class? Is it substitution
    failure (in which case, the function is simply dropped, and the
    compiler chooses the non-template), or is the substitution
    successful, overload resolution then chooses the template
    (because it is a better match) and you get an error, because
    it's illegal to instantiate the template with a local class.
    (The compiler which calls the template function is obviously
    wrong.)

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Jul 15, 2008
    #5
  6. James Kanze

    Fraser Ross Guest

    "Gennaro Prota"
    > First a question: was it intentional that D is a local class? That's
    > the only reason I see for it not to compile (modulo N2580 :)).



    I think it is intentional. The template function is a perfect match
    only if D is not local to main and so has linkage. The non-template
    function is the only one considered otherwise, and is a match with an
    implicit conversion.

    Fraser.
     
    Fraser Ross, Jul 15, 2008
    #6
  7. James Kanze

    Guest

    On 15 juil, 18:22, James Kanze <> wrote:
    > Just ran into an interesting question concerning SFINAE.  Given
    > the following code:
    >
    >     #include <iostream>
    >     #include <typeinfo>
    >
    >     template< typename T >
    >     class P
    >     {
    >     public:
    >         P( T* ) { std::cout << "In P: normal ctor" << std::endl ; }
    >         template< typename U >
    >         P( U* ) { std::cout << "In P: template ctor (U = "
    >                     << typeid( U ).name() << ')' << std::endl ; }
    >     } ;
    >
    >     class B
    >     {
    >     public:
    >         virtual             ~B() {}
    >     } ;
    >
    >     int
    >     main()
    >     {
    >         class D : public B {} ;
    >         P< B > p( new D ) ;
    >         return 0 ;
    >     }
    >
    > Should this compile, and if so, what should the program output?
    > I've got three different compilers at hand: one fails to
    > compile, one outputs "In P: normal ctor", and one outputs "In P:
    > template ctor (U = ...)", where the ... is the mangled name of
    > D.  (My own feeling is that it shouldn't compile.  But I'm not
    > all that clear about template argument deduction, and at what
    > level SFINAE kicks in.)



    In your example, a local class is used as a (deduced) template
    argument. Local classes can't be used as a template argument. SFINAE
    comes when type deduction fails. The C++ standard lists exhaustively
    the cases where type deduction fails. The use of a local class as a
    template argument is not listed as one of those cases.

    Alexandre Courpron.
     
    , Jul 15, 2008
    #7
  8. James Kanze

    James Kanze Guest

    On Jul 15, 7:56 pm, Victor Bazarov <> wrote:
    > James Kanze wrote:
    > > Just ran into an interesting question concerning SFINAE. Given
    > > the following code:


    > > #include <iostream>
    > > #include <typeinfo>


    > > template< typename T >
    > > class P
    > > {
    > > public:
    > > P( T* ) { std::cout << "In P: normal ctor" << std::endl ; }
    > > template< typename U >
    > > P( U* ) { std::cout << "In P: template ctor (U = "
    > > << typeid( U ).name() << ')' << std::endl ; }
    > > } ;


    > > class B
    > > {
    > > public:
    > > virtual ~B() {}
    > > } ;


    > > int
    > > main()
    > > {
    > > class D : public B {} ;
    > > P< B > p( new D ) ;
    > > return 0 ;
    > > }


    > > Should this compile, and if so, what should the program output?
    > > I've got three different compilers at hand: one fails to
    > > compile, one outputs "In P: normal ctor", and one outputs "In P:
    > > template ctor (U = ...)", where the ... is the mangled name of
    > > D. (My own feeling is that it shouldn't compile. But I'm not
    > > all that clear about template argument deduction, and at what
    > > level SFINAE kicks in.)


    > SFINAE would kick in if the type deduction would fail due to the
    > resulting type (or some other element derived from that) is not a
    > "natural" C++ element, but not an explicitly stated cause of
    > ill-formedness. OTOH, the Standard is a bit vague WRT using local types
    > with templates. If you subscribe to the strict spirit of the Standard,
    > then *any* use of local type as a type argument of a template is not
    > allowed (according to [temp.arg.type]/2), so the constructor P(U*) that
    > is instantiated when 'U == D', is an illegal (but not unnatural)
    > construct. In that case SFINAE does not apply. If you subscribe to the
    > relaxed Standard, then you shall only avoid using local types when
    > specifying the template type argument explicitly, but not when you allow
    > it to be deduced from a function call. In that case SFINAE doesn't
    > apply either (since the deduction cannot "fail"), and the templated
    > c-tor is simply used with 'U == D'. Comeau behaves according to the
    > former strategy, VC++ - according to the latter.


    I think that the standard is clear (unless there have been
    clarifications I've missed): you can't instantiate a template
    over a local class. But you've pretty much summed up the crux
    of the problem (at least as I see it): is this a substitution
    failure, or does the substitution work, overload resolution pick
    up the local class, and then you get an error, because
    instantiation over a local class is illegal. That's the opinion
    of Sun CC, and a fairly quick reading of the original standard
    seems to agree with them. But it's all vague enough, and my
    knowledge of this area of the standard is weak enough, that I'm
    really not sure.

    (FWIW: the problem showed up with a bit of code which was
    developed with g++, under Linux. And which passed all of my
    tests. Until I ported it to Sun CC under Solaris:). After
    looking at it, my first reaction was that Sun CC was right, and
    how did g++ miss this. And then SFINAE occured to me; if there
    was a substitution failure, g++ was right. I gave VC++ a try,
    since I had access to it, to get a deciding vote, but it took
    yet another path---the one you describe. And on reading the
    standard, I was even less sure.)

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Jul 15, 2008
    #8
  9. James Kanze

    Guest

    On 15 juil, 21:10, Victor Bazarov <> wrote:
    > wrote:
    > > On 15 juil, 18:22, James Kanze <> wrote:
    > >> Just ran into an interesting question concerning SFINAE.  Given
    > >> the following code:

    >
    > >>     #include <iostream>
    > >>     #include <typeinfo>

    >
    > >>     template< typename T >
    > >>     class P
    > >>     {
    > >>     public:
    > >>         P( T* ) { std::cout << "In P: normal ctor" << std::endl ; }
    > >>         template< typename U >
    > >>         P( U* ) { std::cout << "In P: template ctor (U = "
    > >>                     << typeid( U ).name() << ')' << std::endl ; }
    > >>     } ;

    >
    > >>     class B
    > >>     {
    > >>     public:
    > >>         virtual             ~B() {}
    > >>     } ;

    >
    > >>     int
    > >>     main()
    > >>     {
    > >>         class D : public B {} ;
    > >>         P< B > p( new D ) ;
    > >>         return 0 ;
    > >>     }

    >
    > >> Should this compile, and if so, what should the program output?
    > >> I've got three different compilers at hand: one fails to
    > >> compile, one outputs "In P: normal ctor", and one outputs "In P:
    > >> template ctor (U = ...)", where the ... is the mangled name of
    > >> D.  (My own feeling is that it shouldn't compile.  But I'm not
    > >> all that clear about template argument deduction, and at what
    > >> level SFINAE kicks in.)

    >
    > > In your example, a local class is used as a (deduced) template
    > > argument. Local classes can't be used as a template argument. SFINAE
    > > comes when type deduction fails. The C++ standard lists exhaustively
    > > the cases where type deduction fails.

    >
    > Really?  I thought that the Standard actually listed exhaustively the
    > cases where type deduction *succeeded*.  Everything else fails.  Where
    > is the exhaustive list of failures?  Just point me to the paragraph, no
    > need to quote it.
    >


    Explicit template argument :
    14.8.2/2

    Deduced template argument :
    14.8.2.4 (the whole section, specifically paragraphs 11 to 18)


    Alexandre Courpron.
     
    , Jul 15, 2008
    #9
  10. James Kanze

    Fraser Ross Guest

    "James Kanze"
    I think that the standard is clear (unless there have been
    clarifications I've missed): you can't instantiate a template
    over a local class.

    I feel that the compiler should not attempt to instantiate with a local
    class. After overload resolution failure a diagnostic might refer to
    the local class. The Borland compiler gets everything right as I see
    it. The Comeau compiler reports an error too soon for type deduction
    failure (in broad terms) and strangely twice.

    Fraser.
     
    Fraser Ross, Jul 15, 2008
    #10
  11. James Kanze wrote:
    >> First a question: was it intentional that D is a local class?

    >
    > Obviously. Otherwise, there's no reason for it not to compile,
    > and systematically chose the template constructor.
    >
    >> That's the only reason I see for it not to compile (modulo
    >> N2580 :)).

    >
    > I'll have a glance at the paper you cite,


    Hmm :) Then don't beat me!

    > but the heart of the
    > question, of course, is what happens when template argument
    > deduction comes up with a local class? Is it substitution
    > failure (in which case, the function is simply dropped, and the
    > compiler chooses the non-template), or is the substitution
    > successful, overload resolution then chooses the template
    > (because it is a better match) and you get an error, because
    > it's illegal to instantiate the template with a local class.
    > (The compiler which calls the template function is obviously
    > wrong.)


    OK. I see now. I just stopped when I saw the local class and thought
    to ask before digging further.

    Right now I can't check the standard with the care it deserves, but I
    believe it boils down to this: substitution (deduction) *succeeds*,
    because "usage of local class for template type argument" isn't listed
    as a case of substitution failure; so, a point of instantiation is
    created for both constructors, and that leads to an error for each
    constructor. This is before there's any chance to add the
    instantiations to the overload set, and thus there's really no
    overload resolution. But all this should be backed up with a few
    paragraph numbers from the standard :) I'll try doing that tomorrow.

    --
    Gennaro Prota | <https://sourceforge.net/projects/breeze/>
    Do you need expertise in C++? I'm available.
     
    Gennaro Prota, Jul 15, 2008
    #11
  12. James Kanze

    Joe Greer Guest

    "Fraser Ross" <> wrote in news:487cfcd5$0$5435$c3e8da3
    @news.astraweb.com:

    > "James Kanze"
    > I think that the standard is clear (unless there have been
    > clarifications I've missed): you can't instantiate a template
    > over a local class.
    >
    > I feel that the compiler should not attempt to instantiate with a local
    > class. After overload resolution failure a diagnostic might refer to
    > the local class. The Borland compiler gets everything right as I see
    > it. The Comeau compiler reports an error too soon for type deduction
    > failure (in broad terms) and strangely twice.
    >
    > Fraser.
    >
    >


    I am far from an expert, but it seems to me that it was explicitly
    instantiated with a class B (which is not local, but passed in a D * as an
    argument with a conversion to B *). I could really seeing going either
    way.

    joe
     
    Joe Greer, Jul 15, 2008
    #12
  13. Gennaro Prota wrote:
    > Right now I can't check the standard with the care it deserves, but I
    > believe it boils down to this: substitution (deduction) *succeeds*,
    > because "usage of local class for template type argument" isn't listed
    > as a case of substitution failure; so, a point of instantiation is
    > created for both constructors, and that leads to an error for each
    > constructor. This is before there's any chance to add the instantiations
    > to the overload set, and thus there's really no overload resolution. But
    > all this should be backed up with a few paragraph numbers from the
    > standard :) I'll try doing that tomorrow.


    I couldn't resist checking at least the core issues :) This should be
    useful:

    <http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#488>

    --
    Gennaro Prota | <https://sourceforge.net/projects/breeze/>
    Do you need expertise in C++? I'm available.
     
    Gennaro Prota, Jul 15, 2008
    #13
  14. James Kanze

    Guest

    On 15 juil, 21:45, Victor Bazarov <> wrote:
    > wrote:
    > > On 15 juil, 21:10, Victor Bazarov <> wrote:
    > >> wrote:
    > >>> On 15 juil, 18:22, James Kanze <> wrote:
    > >>>> Just ran into an interesting question concerning SFINAE.  Given
    > >>>> the following code:
    > >>>>     #include <iostream>
    > >>>>     #include <typeinfo>
    > >>>>     template< typename T >
    > >>>>     class P
    > >>>>     {
    > >>>>     public:
    > >>>>         P( T* ) { std::cout << "In P: normal ctor" << std::endl ; }
    > >>>>         template< typename U >
    > >>>>         P( U* ) { std::cout << "In P: template ctor (U = "
    > >>>>                     << typeid( U ).name() << ')' << std::endl ; }
    > >>>>     } ;
    > >>>>     class B
    > >>>>     {
    > >>>>     public:
    > >>>>         virtual             ~B() {}
    > >>>>     } ;
    > >>>>     int
    > >>>>     main()
    > >>>>     {
    > >>>>         class D : public B {} ;
    > >>>>         P< B > p( new D ) ;
    > >>>>         return 0 ;
    > >>>>     }
    > >>>> Should this compile, and if so, what should the program output?
    > >>>> I've got three different compilers at hand: one fails to
    > >>>> compile, one outputs "In P: normal ctor", and one outputs "In P:
    > >>>> template ctor (U = ...)", where the ... is the mangled name of
    > >>>> D.  (My own feeling is that it shouldn't compile.  But I'm not
    > >>>> all that clear about template argument deduction, and at what
    > >>>> level SFINAE kicks in.)
    > >>> In your example, a local class is used as a (deduced) template
    > >>> argument. Local classes can't be used as a template argument. SFINAE
    > >>> comes when type deduction fails. The C++ standard lists exhaustively
    > >>> the cases where type deduction fails.
    > >> Really?  I thought that the Standard actually listed exhaustively the
    > >> cases where type deduction *succeeded*.  Everything else fails.  Where
    > >> is the exhaustive list of failures?  Just point me to the paragraph, no
    > >> need to quote it.

    >
    > > Explicit template argument :
    > > 14.8.2/2

    >
    > > Deduced template argument :
    > > 14.8.2.4 (the whole section, specifically paragraphs 11 to 18)

    >
    > OK, perhaps my understanding of English is failing me, and that's why
    > when I see
    >   "If a substitution in a template parameter or in the function type
    >    of the function template results in an invalid type, type deduction
    >    fails."
    > I just conclude that this is all-inclusive rule, deduction resulting in
    > an invalid type fails.  The last sentence of the third bullet item in
    > the paragraph 2 says "Type deduction *may* fail for the following
    > reasons:" (with a list of the causes that can make deduction fail, the
    > emphasis mine).  To me it sounds too much like an extension of the note
    > it follows, as if it says, "Oh, BTW, here is a list of what *may* happen
    > among other things".  BTW, the use of "may" is very tricky AFA standards
    > are concerned.  There is no certainty in it when it comes to (in this
    > particular case) positive behavior.  It opens the door to the deduction
    > that is allowed to succeed in any of those enumerated situations.  For
    > example, the compiler is *allowed* to deduce the argument even if it
    > results in a pointer to a reference, if such pointer is not used...
    > That is probably why I never considered those lists to be exhaustive
    > enumerations of what is to be treated as the reason for a failure.
    >



    Yes, "may" is often the word where divergences of interpretations
    start. It makes translation of standards in some other languages
    tricky.

    However, the section you are refering to concerns *explicit* template
    arguments. In our case (deduced template argument) the relevant
    section is 14.8.2.4 (specifically /11 to /18 for deduction failures),
    which doesn't contain an all-inclusive rule.

    Alexandre Courpron.
     
    , Jul 15, 2008
    #14
  15. James Kanze

    joseph cook Guest

    On Jul 15, 2:39 pm, James Kanze <> wrote:
    > On Jul 15, 7:54 pm, Gennaro Prota <> wrote:
    >
    >
    >
    >
    >
    > > James Kanze wrote:
    > > > Just ran into an interesting question concerning SFINAE.  Given
    > > > the following code:
    > > >     #include <iostream>
    > > >     #include <typeinfo>
    > > >     template< typename T >
    > > >     class P
    > > >     {
    > > >     public:
    > > >         P( T* ) { std::cout << "In P: normal ctor" << std::endl ; }
    > > >         template< typename U >
    > > >         P( U* ) { std::cout << "In P: template ctor (U = "
    > > >                     << typeid( U ).name() << ')' << std::endl ; }
    > > >     } ;
    > > >     class B
    > > >     {
    > > >     public:
    > > >         virtual             ~B() {}
    > > >     } ;
    > > >     int
    > > >     main()
    > > >     {
    > > >         class D : public B {} ;
    > > >         P< B > p( new D ) ;
    > > >         return 0 ;
    > > >     }
    > > > Should this compile, and if so, what should the program output?
    > > > I've got three different compilers at hand: one fails to
    > > > compile, one outputs "In P: normal ctor", and one outputs "In P:
    > > > template ctor (U = ...)", where the ... is the mangled name of
    > > > D.  (My own feeling is that it shouldn't compile.  But I'm not
    > > > all that clear about template argument deduction, and at what
    > > > level SFINAE kicks in.)

    > > First a question: was it intentional that D is a local class?

    >
    > Obviously.  Otherwise, there's no reason for it not to compile,
    > and systematically chose the template constructor.
    >
    > > That's the only reason I see for it not to compile (modulo
    > > N2580 :)).

    >
    > I'll have a glance at the paper you cite,


    That should be easy since you wrote it.

    Joe Cook
     
    joseph cook, Jul 15, 2008
    #15
  16. James Kanze

    Fraser Ross Guest

    "Joe Greer"
    > I am far from an expert, but it seems to me that it was explicitly
    > instantiated with a class B (which is not local, but passed in a D *

    as an
    > argument with a conversion to B *). I could really seeing going

    either
    > way.


    Its explicitly instantiated as so:
    P< B >

    The type of "new D" is unimportant in deciding the type of T. Are you
    aware that there isn't implicit conversions involved in template
    argument deduction? U can't be B.

    Fraser.
     
    Fraser Ross, Jul 15, 2008
    #16
  17. Gennaro Prota wrote:
    > Right now I can't check the standard with the care it deserves, but
    > I believe it boils down to this: substitution (deduction) *succeeds*,
    > because "usage of local class for template type argument" isn't listed
    > as a case of substitution failure; so, a point of instantiation is
    > created for both constructors, and that leads to an error for each
    > constructor. This is before there's any chance to add the instantiations
    > to the overload set, and thus there's really no overload resolution. But
    > all this should be backed up with a few paragraph numbers from the
    > standard :) I'll try doing that tomorrow.


    Sorry, of course that's *one* error, not an error for each
    constructor; I should refrain from posting at the end of a day like
    yesterday was. Apart from that oversight, I think the analysis is
    correct.

    The text of core issue 488, which I linked to in the other post,
    already mentions the relevant sections of the standard, particularly
    14.8.2 [temp.deduct] par. 2 and the fact that substituting a local
    type isn't listed there as a SFINAE case. (In and of itself that
    section concerns the case of explicitly specified template arguments,
    but then the deduced case is re-conducted back to the former). Just
    let me add that we could just write

    class B;

    class P
    {
    public:
    P( B * );
    template< typename U >
    P( U * );
    } ;

    class B
    {
    public:
    virtual ~B() {}
    } ;

    int
    main()
    {
    class D : public B {} ;
    P p( new D ) ;
    return 0 ;
    }

    (i.e. make P an ordinary class; who needs smart *P*ointers to be
    templates :)) and still have the same problem (in C++03):
    substitution works and an ill-formed declaration is then
    instantiated.

    PS: VC++ should get this right with /Za. If it doesn't then this is a
    regression with respect to at least VC++ 2005 (I'm assuming you are
    using 2008).

    --
    Gennaro Prota | <https://sourceforge.net/projects/breeze/>
    Do you need expertise in C++? I'm available.
     
    Gennaro Prota, Jul 16, 2008
    #17
  18. James Kanze

    James Kanze Guest

    On Jul 15, 11:36 pm, joseph cook <> wrote:
    > On Jul 15, 2:39 pm, James Kanze <> wrote:


    [...]
    > > > First a question: was it intentional that D is a local class?


    > > Obviously. Otherwise, there's no reason for it not to compile,
    > > and systematically chose the template constructor.


    > > > That's the only reason I see for it not to compile (modulo
    > > > N2580 :)).


    > > I'll have a glance at the paper you cite,


    > That should be easy since you wrote it.


    So it is. It also has absolutely nothing to do with the
    question at hand. Since Gennaro put a smiley there, I suppose
    the reference was meant as some sort of a joke. Or maybe he
    simply mistyped the number.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Jul 16, 2008
    #18
  19. James Kanze

    James Kanze Guest

    On Jul 15, 10:10 pm, Joe Greer <> wrote:
    > "Fraser Ross" <> wrote in news:487cfcd5$0$5435$c3e8da3
    > @news.astraweb.com:


    > > "James Kanze"
    > > > I think that the standard is clear (unless there have been
    > > > clarifications I've missed): you can't instantiate a
    > > > template over a local class.


    > > I feel that the compiler should not attempt to instantiate with a local
    > > class. After overload resolution failure a diagnostic might refer to
    > > the local class. The Borland compiler gets everything right as I see
    > > it. The Comeau compiler reports an error too soon for type deduction
    > > failure (in broad terms) and strangely twice.


    > I am far from an expert, but it seems to me that it was
    > explicitly instantiated with a class B (which is not local,
    > but passed in a D * as an argument with a conversion to B *).
    > I could really seeing going either way.


    The type of the object is clear. The problem is in the
    resolution of the call to the constructor, and how type
    deduction works.

    From other postings, I gather that the committee has fixed this
    by allowing instantiation over local types. And I gather that
    there was more or less a consensus in the committee (or at least
    those members addressing the issue), that the code was illegal
    according to the original standard.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Jul 16, 2008
    #19
  20. James Kanze wrote:
    [...]
    >>>> That's the only reason I see for it not to compile (modulo
    >>>> N2580 :)).

    >
    >>> I'll have a glance at the paper you cite,

    >
    >> That should be easy since you wrote it.

    >
    > So it is. It also has absolutely nothing to do with the
    > question at hand. Since Gennaro put a smiley there, I suppose
    > the reference was meant as some sort of a joke. Or maybe he
    > simply mistyped the number.


    Yes, it was meant as a joke (sorry if it failed to be so), since
    you've longly been in the (correct) habit of including both <ostream>
    and <iostream> in such cases.

    --
    Gennaro Prota | <https://sourceforge.net/projects/breeze/>
    Do you need expertise in C++? I'm available.
     
    Gennaro Prota, Jul 16, 2008
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Peter Collingbourne

    problem with SFINAE applied to class methods

    Peter Collingbourne, Jul 1, 2004, in forum: C++
    Replies:
    8
    Views:
    477
    Pete Becker
    Jul 4, 2004
  2. Replies:
    3
    Views:
    1,672
    Attila Feher
    Feb 8, 2005
  3. Clark S. Cox III

    Using SFINAE with constructors

    Clark S. Cox III, Sep 9, 2005, in forum: C++
    Replies:
    2
    Views:
    382
    Howard Hinnant
    Sep 9, 2005
  4. christopher diggins

    SFINAE problem.

    christopher diggins, Sep 26, 2005, in forum: C++
    Replies:
    4
    Views:
    461
    christopher diggins
    Sep 26, 2005
  5. SFINAE

    , Apr 26, 2006, in forum: C++
    Replies:
    4
    Views:
    477
    n2xssvv g02gfr12930
    Apr 26, 2006
Loading...

Share This Page