detecting a constructor with a specific signature

I'm trying to create a type trait to detect the presence of a constructor with a very specific signature. Types passed to this trait will *always* have a constructor of the form: T( const std::string& ); but some of them will have this constructor as well: T( const std::string&, Foo& ); // Second parameter will always be a Foo& I would like to create a type trait that returns true when the second constructor is present. I can't simply do: !is_convertible<std::string, T>::value since that will return false when the second constructor is present since all Ts are convertible from std::string. Is it possible to create such a trait?

AMDG Kenny Riddile wrote:
I'm trying to create a type trait to detect the presence of a constructor with a very specific signature. Types passed to this trait will *always* have a constructor of the form:
T( const std::string& );
but some of them will have this constructor as well:
T( const std::string&, Foo& ); // Second parameter will always be a Foo&
I would like to create a type trait that returns true when the second constructor is present. I can't simply do:
!is_convertible<std::string, T>::value
since that will return false when the second constructor is present since all Ts are convertible from std::string. Is it possible to create such a trait?
As far as I know, it's impossible. In Christ, Steven Watanabe

Kenny Riddile wrote:
I'm trying to create a type trait to detect the presence of a constructor with a very specific signature. Types passed to this trait will *always* have a constructor of the form:
T( const std::string& );
but some of them will have this constructor as well:
T( const std::string&, Foo& ); // Second parameter will always be a Foo&
I would like to create a type trait that returns true when the second constructor is present. I can't simply do:
!is_convertible<std::string, T>::value
since that will return false when the second constructor is present since all Ts are convertible from std::string. Is it possible to create such a trait?
As Steven Watanabe noted, "AFAIK, it's impossible." These sound like very specific constructors that you're looking for, however, so it might be reasonable to use a "flag typedef" within the class (intrusive) and/or an explicitly specialized metafunction (non-intrusive)...? - Jeff

Jeffrey Hellrung wrote:
As Steven Watanabe noted, "AFAIK, it's impossible."
These sound like very specific constructors that you're looking for, however, so it might be reasonable to use a "flag typedef" within the class (intrusive) and/or an explicitly specialized metafunction (non-intrusive)...?
- Jeff
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Ya, I was already using the "flag typedef" method, but was just wondering if something non-intrusive was feasible...maybe it isn't. A compiler with 0x support isn't an option I'm afraid.

On 27.01.2010, at 15:52, Kenny Riddile wrote:
Ya, I was already using the "flag typedef" method, but was just wondering if something non-intrusive was feasible...maybe it isn't. A compiler with 0x support isn't an option I'm afraid.
No need for C++0x if you only need a special case. Requires a good compiler, though, GCC 4.3 is not good enough, 4.4+ is. The following compiles with GCC 4.4, -ansi -pedantic, replacing decltype with sizeof :) #include <string> #include <iostream> struct Foo { Foo( const std::string& ); }; struct Bar { Bar( const std::string& ); Bar( const std::string&, Foo& ); }; template< typename T > T make(); template< int > struct result { typedef double type; }; template< typename T > typename result< sizeof T( make< const std::string& >(), make< Foo& >() ) >::type select( int ); template< typename > char select( ... ); template< typename T > struct has_foo_ctor { enum { value = sizeof select< T >( 0 ) > 1 }; }; int main() { std::cout << has_foo_ctor< Foo >::value << std::endl; std::cout << has_foo_ctor< Bar >::value << std::endl; } Regards, Daniel

Daniel Frey wrote:
On 27.01.2010, at 15:52, Kenny Riddile wrote:
Ya, I was already using the "flag typedef" method, but was just wondering if something non-intrusive was feasible...maybe it isn't. A compiler with 0x support isn't an option I'm afraid.
No need for C++0x if you only need a special case. Requires a good compiler, though, GCC 4.3 is not good enough, 4.4+ is. The following compiles with GCC 4.4, -ansi -pedantic, replacing decltype with sizeof :)
#include <string> #include <iostream>
struct Foo { Foo( const std::string& ); };
struct Bar { Bar( const std::string& ); Bar( const std::string&, Foo& ); };
template< typename T > T make();
template< int > struct result { typedef double type; };
template< typename T > typename result< sizeof T( make< const std::string& >(), make< Foo& >() ) >::type select( int );
template< typename > char select( ... );
template< typename T > struct has_foo_ctor { enum { value = sizeof select< T >( 0 ) > 1 }; };
int main() { std::cout << has_foo_ctor< Foo >::value << std::endl; std::cout << has_foo_ctor< Bar >::value << std::endl; }
Regards, Daniel
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Alas, I'm using VC9. The first declaration of select() gives me the following error: error C2564: 'T' : a function-style conversion to a built-in type can only take one argument

----- Original Message ----- From: "Kenny Riddile" <kfriddile@yahoo.com> To: <boost@lists.boost.org> Sent: Wednesday, January 27, 2010 6:14 PM Subject: Re: [boost] detecting a constructor with a specific signature
Daniel Frey wrote:
On 27.01.2010, at 15:52, Kenny Riddile wrote:
Ya, I was already using the "flag typedef" method, but was just wondering if something non-intrusive was feasible...maybe it isn't. A compiler with 0x support isn't an option I'm afraid.
No need for C++0x if you only need a special case. Requires a good compiler, though, GCC 4.3 is not good enough, 4.4+ is. The following compiles with GCC 4.4, -ansi -pedantic, replacing decltype with sizeof :)
#include <string> #include <iostream>
struct Foo { Foo( const std::string& ); };
struct Bar { Bar( const std::string& ); Bar( const std::string&, Foo& ); };
template< typename T > T make();
template< int > struct result { typedef double type; };
template< typename T > typename result< sizeof T( make< const std::string& >(), make< Foo& >() ) >::type select( int );
template< typename > char select( ... );
template< typename T > struct has_foo_ctor { enum { value = sizeof select< T >( 0 ) > 1 }; };
int main() { std::cout << has_foo_ctor< Foo >::value << std::endl; std::cout << has_foo_ctor< Bar >::value << std::endl; }
Regards, Daniel
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Alas, I'm using VC9. The first declaration of select() gives me the following error:
error C2564: 'T' : a function-style conversion to a built-in type can only take one argument
Hi, have you tried to double () template< typename T > typename result< sizeof T(( make< const std::string& >(), make< Foo& >() )) >::type select( int ); Vicente

AMDG vicente.botet wrote:
"Kenny Riddile" <kfriddile@yahoo.com> wrote:
Alas, I'm using VC9. The first declaration of select() gives me the following error:
error C2564: 'T' : a function-style conversion to a built-in type can only take one argument
Hi,
have you tried to double ()
template< typename T > typename result< sizeof T(( make< const std::string& >(), make< Foo& >() )) >::type select( int );
That doesn't try the same constructor. The problem is that this method requires extended SFINAE which VC9 doesn't support. In Christ, Steven Watanabe

----- Original Message ----- From: "Steven Watanabe" <watanabesj@gmail.com> To: <boost@lists.boost.org> Sent: Wednesday, January 27, 2010 6:32 PM Subject: Re: [boost] detecting a constructor with a specific signature
AMDG
vicente.botet wrote:
"Kenny Riddile" <kfriddile@yahoo.com> wrote:
Alas, I'm using VC9. The first declaration of select() gives me the following error:
error C2564: 'T' : a function-style conversion to a built-in type can only take one argument
Hi,
have you tried to double ()
template< typename T > typename result< sizeof T(( make< const std::string& >(), make< Foo& >() )) >::type select( int );
That doesn't try the same constructor.
The problem is that this method requires extended SFINAE which VC9 doesn't support.
You are right, my proposal test if there is a constructor with an argument Foo&, isn't it? I confirm it works for gcc-4.4.0 and fails to compile for gcc-4.3.2 and MSVC v9. Steven, does this mean that it is possible to implement the trait with a good C++98 compiler? Or there are other things missing yet? Thanks, Vicente

vicente.botet wrote:
Hi,
have you tried to double ()
template< typename T > typename result< sizeof T(( make< const std::string& >(), make< Foo& >() )) >::type select( int );
Vicente
Ya, I thought of that right after posting and it does fix the compilation error. The issue I'm having now is that both has_foo_ctor< Foo >::value has_foo_ctor< Bar >::value are evaluating to true and I'm not sure why.

AMDG Kenny Riddile wrote:
vicente.botet wrote:
have you tried to double ()
template< typename T > typename result< sizeof T(( make< const std::string& >(), make< Foo&
() )) >::type select( int );
Ya, I thought of that right after posting and it does fix the compilation error. The issue I'm having now is that both
has_foo_ctor< Foo >::value has_foo_ctor< Bar >::value
are evaluating to true and I'm not sure why.
When you use double parentheses, it calls the comma operator and only passes a single argument to the constructor. In Christ, Steven Watanabe

On 26.01.2010, at 23:36, Kenny Riddile wrote:
I'm trying to create a type trait to detect the presence of a constructor with a very specific signature.
You might want to have a look into is_constructible. It's a new type trait from the upcoming standard <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n3000.pdf>, and a partial implementation is possible. Here's a version for GCC 4.4+ (requires -std=c++0x): #include <type_traits> namespace boost { namespace is_constructible_impl { template< typename T > typename std::add_rvalue_reference< T >::type declval(); template< typename T > decltype( T(), std::true_type() ) select( int ); template< typename T, typename A > decltype( static_cast< T >( declval< A >() ), std::true_type() ) select( int ); template< typename T, typename A1, typename A2 > decltype( T( declval< A1 >(), declval< A2 >() ), std::true_type() ) select( int ); template< typename T, typename A1, typename A2, typename A3 > decltype( T( declval< A1 >(), declval< A2 >(), declval< A3 >() ), std::true_type() ) select( int ); template< typename T, typename A1, typename A2, typename A3, typename A4 > decltype( T( declval< A1 >(), declval< A2 >(), declval< A3 >(), declval< A4 >() ), std::true_type() ) select( int ); // A variadic version of the above is not possible, // GCC 4.4 crashes with an internal compiler error. // GCC 4.5 will likely provide is_constructible itself template< typename, typename... > std::false_type select( ... ); } template< typename T, typename... As > struct is_constructible : std::is_same< decltype( is_constructible_impl::select< T, As... >( 0 ) ), std::true_type > { }; } HTH. Regards, Daniel

Daniel Frey-3 wrote:
On 26.01.2010, at 23:36, Kenny Riddile wrote:
I'm trying to create a type trait to detect the presence of a constructor with a very specific signature.
You might want to have a look into is_constructible. It's a new type trait from the upcoming standard <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n3000.pdf>, and a partial implementation is possible. Here's a version for GCC 4.4+ (requires -std=c++0x):
#include <type_traits>
namespace boost { namespace is_constructible_impl { template< typename T > typename std::add_rvalue_reference< T >::type declval();
template< typename T > decltype( T(), std::true_type() ) select( int );
template< typename T, typename A > decltype( static_cast< T >( declval< A >() ), std::true_type() ) select( int );
template< typename T, typename A1, typename A2 > decltype( T( declval< A1 >(), declval< A2 >() ), std::true_type() ) select( int );
template< typename T, typename A1, typename A2, typename A3 > decltype( T( declval< A1 >(), declval< A2 >(), declval< A3 >() ), std::true_type() ) select( int );
template< typename T, typename A1, typename A2, typename A3, typename A4 > decltype( T( declval< A1 >(), declval< A2 >(), declval< A3 >(), declval< A4 >() ), std::true_type() ) select( int );
// A variadic version of the above is not possible, // GCC 4.4 crashes with an internal compiler error. // GCC 4.5 will likely provide is_constructible itself
template< typename, typename... > std::false_type select( ... ); }
template< typename T, typename... As > struct is_constructible : std::is_same< decltype( is_constructible_impl::select< T, As... >( 0 ) ), std::true_type > { }; }
HTH.
Regards, Daniel
Hi, glad to hear that a partial solution exists. Can this be emulated with Boost.Typeof on C++98 compilers? Best, Vicente -- View this message in context: http://old.nabble.com/detecting-a-constructor-with-a-specific-signature-tp27... Sent from the Boost - Dev mailing list archive at Nabble.com.

Kenny Riddile wrote:
I'm trying to create a type trait to detect the presence of a constructor with a very specific signature. Types passed to this trait will *always* have a constructor of the form:
T( const std::string& );
but some of them will have this constructor as well:
T( const std::string&, Foo& ); // Second parameter will always be a Foo&
I would like to create a type trait that returns true when the second constructor is present. I can't simply do:
!is_convertible<std::string, T>::value
since that will return false when the second constructor is present since all Ts are convertible from std::string. Is it possible to create such a trait?
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Well, I found a compromise that I'm happy with. Since the vast majority of these types will not have the "extra" constructor, I mandated that types that do have it derive from a specific type. Then I can simply use boost::is_base_of to detect them. At least this solution is only intrusive to types that already desire special treatment. Thanks for the help guys...looks like I'll have to wait for widespread std::is_constructible support before revisiting this.
participants (6)
-
Daniel Frey
-
Jeffrey Hellrung
-
Kenny Riddile
-
Steven Watanabe
-
Vicente Botet Escriba
-
vicente.botet