Some type transformations in <type_traits> can also be expressed using core language syntax (e.g. std::add_const<T>::type is/seems equivalent to const T). Dtto for std::add_lvalue_reference, and perhaps others. What is the use for these type traits?
I fully understand the standard would be providing an "incomplete toolbox" without them, and I can imagine use in a meta way, something like this:
template<typename In, template <typename> class Modifier>
struct Apply {
typedef typename Modifier<T>::type Out;
};
Apply<int, std::add_const>
Are there any other use cases for these traits which can be expressed syntactically, or are they just included "out of a sense of completeness" and for the occasional meta-use?
Those traits come from Boost and the proposal to add them to the standard, N1345, quotes Andrei Alexandrescu as saying:
"I understand the symmetry argument for adding add_const, add_volatile, add_cv, and add_pointer, however I would argue in favor of eliminating them. The language-provided equivalents are just simpler and nicer."
The same proposal also gives this rationale:
Author's Note: superficially the add_const, add_volatile and add_cv classes are irrelevant, since, for example, add_const::type is the same as T const, for all T (currently this does not apply to function types - but issue 295 addresses this). However the experience from boost is that several users have asked for these templates to be present in the library for the following reasons: (a) Some users find these more explicit - when combining transformation templates in particular, users like the kind of "built in documentation" that these templates provide. (b) Not all users are aware that cv-qualifying a reference is allowed and has no effect, or that cv-qualifying a type that is already cv-qualified is allowed and has no effect. (c) Compilers may emit warnings when cv-qualifying a type that is a reference, or already has a cv-qualifier, these templates can be implemented such that these messages are suppressed in these cases.
Also, for add_reference (renamed to add_lvalue_reference in the standard):
Author's Note: the add_reference template was one of the original motivations behind the boost type traits library. However the resolution to issue 106 makes the template appear largely redundant. In spite of that add_reference may well be useful in suppressing compiler warnings when inadvertently creating references to references in template code.
These traits are provided for occasional meta-use. It makes it possible to transport wanted cv-qualifiers around in meta programming.
template<class T,template<class> class Trait>
struct transform
{
/* working with T creating newT*/
typedef Trait<newT>::type type;
};
template<class T>
struct special_transform
: transfrom<T, std::add_const>
{};
In this case you could not replace std::add_const with const.
add_const can be used to resolve type deduction conflicts.
template <typename T>
class wrapper;
template <typename T>
bool operator==(wrapper<T> const& w, T const& t);
Problems arise if we use wrapper<T const>:
wrapper<int const> w = { 42 };
assert(w == 42); // Error: conflicting deduced types
T is simultaneously deduced to be both int and int const. This can be resolved using add_const:
template <typename T>
bool operator==(wrapper<T> const& w, add_const_t<T>& t);
The only use case I know is illustrated below:
struct F
{
bool f() const { return true; }
bool f() { return false; }
};
assert(!F{}.f())
assert(std::add_const_t< F >{}.f());
It also needed for testing of cv-ref-qualified member-functions functionality, that may differs for different overloadings (only for lref-qualified modern C++ has handy std::as_const function):
struct F
{
int g() & { return 1; }
int g() const & { return 2; }
int g() && { return 3; }
int g() const && { return 4; }
};
F f;
assert(f.g() == 1);
assert(std::as_const(f).g() == 2);
assert(F{}.g() == 3);
assert(std::add_const_t< F >{}.g() == 4); // rarely needed, but if needed, then it helps
Related
I've been using C# so long, I have a couple of questions about function templates in C++.
template <typename T>
T max(T x, T y)
{
return (x > y) ? x : y;
}
Why do some examples use typename and other examples use class in the template parameter declaration? What is the difference?
Is there any way to restrict T to a particular type, or to a type that derives from a particular type?
Is there any way for a class to have two methods with the same name, except one is templated and the other is not?
UPDATE:
I appreciate all the answers, but several of them contain examples that I won't compile when I try to apply them to my code.
To clarify question 3, I have the following method:
template<typename T>
std::unique_ptr<T> ExecuteSqlQuery(LPCTSTR pszSqlQuery, UINT nOpenType = AFX_DB_USE_DEFAULT_TYPE);
I would like to declare a variation of this that uses CRecordset as T, so that either of the following statements would be valid:
auto result = db.ExecuteSqlQuery<CCustomerRecordset>(L"SELECT ...");
auto result = db.ExecuteSqlQuery(L"SELECT ...");
Why do some examples use typename and other examples use class in the template parameter declaration? What is the difference?
There is no difference between the two in the template parameter declaration, however they both have additional separate meanings in other contexts. E.g. typename is used to mark dependent names as type names and class is used to introduce a class declaration.
Is there any way to restrict T to a particular type, or a type that derives from a particular type?
Yes, one way is to rely on SFINAE to discard instantiations of types satisfying some condition, often facilitated by std::enable_if, e.g. (using C++14):
template<typename T, typename = std::enable_if_t<std::is_base_of_v<SomeBaseClass, T>>
T max(T x, T y)
{
return (x > y) ? x : y;
}
In the upcoming C++20, there will be support for Concepts, which allow one to write
template<std::DerivedFrom<SomeBaseClass> T>
T max(T x, T y)
{
return (x > y) ? x : y;
}
Is there any way for a class to have two methods with the same name, except one is templated and the other is not?
Yes, this is possible. In overload resolution, if both candidates would be equally well matching, the non-templated one will be preferred.
In this particular context both class and typename mean exaclty the same, there is no difference. class is just a bit shorter :-).
Until C++20 we could try and restrict template arguments using sophisticated template metaprogramming in conjunction with SFINAE technique. Basically, it makes template instantiation fail if the argument does not satisfy some condition. While it's very powerfull approach, it has its drawbacks: increased compile times and very long and unclear error messages.
In C++20 we have a new language feature named concepts, which is aimed to do exactly the same in a simple and straightforward way.
Yes, a function template can be overloaded with a regular function. If the both match, the regular function will be chosen. Note however that in general template overload resolution is quite complicated topic.
Why do some examples use typename and other examples use class in the template parameter declaration? What is the difference?
Historically,
Only typename was allowed for simple template, and class should be used for template template parameter:
template <template <typename> class C> void foo();
with usage such as
foo<std::unique_ptr>();
There are now (C++17) interchangeable in those contexts.
Is there any way to restrict T to a particular type, or to a type that derives from a particular type?
You might do that with SFINAE (which has several syntaxes), and in C++20 with Concepts.
template <typename T>
std::enable_if_t<some_trait<T>::value> foo();
Is there any way for a class to have two methods with the same name, except one is templated and the other is not?
Yes you might have several overloads that way
template <template <class> typename C> void foo();
template <int> void foo();
void foo();
or more simply
template <typename T> void foo(T); // #1
void foo(int); // #2
// Note that foo<int> (#1 with T = int) is different than foo (#2)
Old school C++ used 'class', but we now use 'typename'. You can still use class, but typename is recommended.
Yes, you can restrict types via specialisation..
template<typename T> T foo(T x); //< no implementation in the generic case
template<> T foo<float>(T x) { return x; } //< float is allowed
template<> T foo<double>(T x) { return x; } //< double is allowed
And you can handle derived types as well (and there are a few ways to do this)
#include <string>
#include <iostream>
struct Cow {};
template<typename T>
struct Moo
{
// default to false
template<bool valid = std::is_base_of<Cow, T>::value>
static void moo()
{
std::cout << "No moo for you!" << std::endl;
}
// moo if T is a cow
template<>
static void moo<true>()
{
std::cout << "Mooooo!" << std::endl;
}
};
struct AberdeenAngus : public Cow {};
struct Sheep {};
int main()
{
Moo<AberdeenAngus>::moo();
Moo<Sheep>::moo();
return 0;
}
Yes.
class Foo
{
public:
template<typename T>
T thing(T a) { return a; } //< template
float thing(float a) { return a * 5.0f; } //< function overload
};
When using the compile-time duck typing inherent with the template style, is there any way to enforce the requirement that the template argument implements certain methods with certain signatures?
struct ProtocolT {
void g() const;
void h();
}
// I want the compiler to check that T conforms to ProtocolT
// that is, T must implement g() and h() rather than just g()
template <typename T>
void f(const T& x) {
x.g();
}
Of course, even without this, there is perfect type safety: if the template argument T does not have a method used in the template function implementation, the compiler will always complain.
But I find it appealing to state clearly that class T must have all the methods specified in some class ProtocolT. It would allow me to constrain the design earlier in the development process by requiring methods from T that I don't yet use in the template function implementation.
Even if I didn't include any unused methods in ProtocolT, I still think a verified protocol conformance would help when I need to write a class usable as T. (Of course, no one stops me from writing ProtocolT for documentation purposes, but then the compiler won't validate that ProtocolT includes at least all the required methods.)
The feature you are looking for is known as concepts. They are currently a technical specification; GCC has an implementation of concepts lite.
Using concepts would look something like (I'm not too familiar with the syntax, so it would probably be slightly different):
template <typename T>
concept bool Protocol = requires(const T a, T b) {
{ a.g() } -> void;
{ b.h() } -> void;
};
void f(const Protocol& x) {
x.g();
}
However, if you want a solution you can use right now, you can emulate concepts with a variety of techniques.
You could write type-traits to detect if a function does what you want.
You could also use the detection idiom, which abstracts the previous technique, greatly reducing boilerplate. For your example:
template <typename T>
using g_t = decltype(std::declval<const T&>().g());
template <typename T>
using h_t = decltype(std::declval<T&>().h());
template <typename T>
constexpr bool meets_protocol_v = std::experimental::is_detected_exact_v<void, g_t, T>
&& std::experimental::is_detected_exact_v<void, h_t, T>;
In using it, you could either be SFINAE friendly and SFINAE off of meets_protocol_v, or you could static assert:
template <typename T>
void f(const T& x) {
static_assert(meets_protocol_v<T>, "Doesn't meet protocol");
x.g();
}
Maybe inserting corresponding static_assert:
static_assert
(
::std::is_same< void, decltype(::std::declval< T >().h()) >::value
, "T must implement void h(void)"
);
Also note that in your example when T follows ProtocolT requirements it still won't work because f accepts a const reference to T, while ProtocolT only says it should have non-const g().
In my template-ized function, I'm trying to check the type T is of a specific type. How would I do that?
p/s I knew the template specification way but I don't want to do that.
template<class T> int foo(T a) {
// check if T of type, say, String?
}
Thanks!
Instead of checking for the type use specializations. Otherwise, don't use templates.
template<class T> int foo(T a) {
// generic implementation
}
template<> int foo(SpecialType a) {
// will be selected by compiler
}
SpecialType x;
OtherType y;
foo(x); // calls second, specialized version
foo(y); // calls generic version
If you don't care about compile-time, you may use boost::is_same.
bool isString = boost::is_same<T, std::string>::value;
As of C++11, this is now part of the standard library
bool isString = std::is_same<T, std::string>::value
hmm because I had a large portion of
same code until the 'specification'
part.
You can use overloading, but if a large part of the code would work for any type, you might consider extracting the differing part into a separate function and overload that.
template <class T>
void specific(const T&);
void specific(const std::string&);
template <class T>
void something(const T& t)
{
//code that works on all types
specific(t);
//more code that works on all types
}
I suppose you could use the std::type_info returned by the typeid operator
I suspect someone should tell you why it might not be a good idea to avoid using overloading or specialization. Consider:
template<class T> int foo(T a) {
if(isAString<T>()) {
return a.length();
} else {
return a;
}
}
You might think on a first sight that it will work for int too, because it will only try to call length for strings. But that intuition is wrong: The compiler still checks the string branch, even if that branch is not taken at runtime. And it will find you are trying to call a member function on non-classes if T is an int.
That's why you should separate the code if you need different behavior. But better use overloading instead of specialization, since it's easier to get a clue how things work with it.
template<class T> int foo(T a) {
return a;
}
int foo(std::string const& a) {
return a.length();
}
You have also better separated the code for different paths of behavior. It's not all anymore clued together. Notice that with overloading, the parameters may have different type forms and the compiler will still use the correct version if both match equally well, as is the case here: One can be a reference, while the other can not.
You can check using type_traits (available in Boost and TR1) (e.g. is_same or is_convertible) if you really want to avoid specialization.
You can perform static checks on the type that you have received (look at the boost type traits library), but unless you use specialization (or overloads, as #litb correctly points out) at one point or another, you will not be able to provide different specific implementations depending on the argument type.
Unless you have a particular reason (which you could add to the question) not to use the specialization in the interface just do specialize.
template <> int subtract( std::string const & str );
If you are using C++11 or later, std::is_same does exactly what you want:
template <typename T>
constexpr bool IsFloat() { return std::is_same<T, float>::value; }
template <typename T>
void SomeMethodName() {
if (IsFloat<T>()) {
...
}
}
http://en.cppreference.com/w/cpp/types/is_same
Consider the following function template:
template<typename T> void Foo(T)
{
// ...
}
Pass-by-value semantics make sense if T happens to be an integral type, or at least a type that's cheap to copy.
Using pass-by-[const]-reference semantics, on the other hand, makes more sense if T happens to be an expensive type to copy.
Let's assume for a second that you are writing a library. Ideally, as a library implementer, your job is to provide your consumers with a clean API that is both as generic and efficient as possible. How then, do you provide a generic interface that caters to both types of argument passing strategies?
Here is my first attempt at getting this to work:
#include <boost/type_traits.hpp>
template<typename T> struct DefaultCondition
{
enum {value = boost::is_integral<T>::value /* && <other trait(s)> */};
};
template< typename T, class Condition = DefaultCondition<T> > class Select
{
template<bool PassByValue = Condition::value, class Dummy = void> struct Resolve
{
typedef T type;
};
template<class Dummy> struct Resolve<false, Dummy>
{
typedef const T& type;
};
public: typedef typename Resolve<>::type type;
};
Typical usage:
template<typename T> class EnterpriseyObject
{
typedef typename Select<T>::type type;
public: explicit EnterpriseyObject(type)
{
// ...
}
};
struct CustomType {};
void Usage()
{
EnterpriseyObject<int>(0); // Pass-by-value.
(EnterpriseyObject<CustomType>(CustomType())); // Pass-by-const-reference.
}
This, of course, indirectly breaks implicit template argument deduction for non-class templates:
template<typename T> void Foo(typename Select<T>::type)
{
// ...
}
void Usage()
{
Foo(0); // Incomplete.
Foo<int>(0); // Fine.
}
This can be "fixed" with the Boost.Typeof library and a macro, a la the WinAPI:
#define Foo(Arg) ::Foo<BOOST_TYPEOF((Arg))>((Arg))
Though this is just a quasi-portable hack.
As you can see, my general approach is not really satisfactory for all cases.
As a hobbyist programmer, I neither have real-world experience nor do I have access to production-quality code for reference. I also realize that this might seem like a bad case of premature optimization, but I'm genuinely interested in a couple of things:
Do you, or have you used this type of optimization* in the past?
Does the Boost (or any other public) library already provide similar functionality?
If the answer to #1 or #2 is a 'yes' -- how is the non-class template case handled?
Are there any obvious pitfalls that I'm not seeing with something like this?
Finally, is this even a sane thing to do?
* Not profiled. ;)
Yes. All the time. I use it myself.
Yes, use Boost.Utility's Call Traits :)
Usage would be...
template <typename T>
void foo(boost::call_traits<T>::param_type param)
{
// Use param
}
As far as I know, non-class templates are passed-by-value unless it is faster to not. Thanks to partial template specialization, it can be customized relatively easily.
Sorry, didn't really read what you did, it just looked like exactly what I went through a few months ago. Therefore, can't really answer this one. My recommendation is just to read through Boost.Utility.
Of course!
In my template-ized function, I'm trying to check the type T is of a specific type. How would I do that?
p/s I knew the template specification way but I don't want to do that.
template<class T> int foo(T a) {
// check if T of type, say, String?
}
Thanks!
Instead of checking for the type use specializations. Otherwise, don't use templates.
template<class T> int foo(T a) {
// generic implementation
}
template<> int foo(SpecialType a) {
// will be selected by compiler
}
SpecialType x;
OtherType y;
foo(x); // calls second, specialized version
foo(y); // calls generic version
If you don't care about compile-time, you may use boost::is_same.
bool isString = boost::is_same<T, std::string>::value;
As of C++11, this is now part of the standard library
bool isString = std::is_same<T, std::string>::value
hmm because I had a large portion of
same code until the 'specification'
part.
You can use overloading, but if a large part of the code would work for any type, you might consider extracting the differing part into a separate function and overload that.
template <class T>
void specific(const T&);
void specific(const std::string&);
template <class T>
void something(const T& t)
{
//code that works on all types
specific(t);
//more code that works on all types
}
I suppose you could use the std::type_info returned by the typeid operator
I suspect someone should tell you why it might not be a good idea to avoid using overloading or specialization. Consider:
template<class T> int foo(T a) {
if(isAString<T>()) {
return a.length();
} else {
return a;
}
}
You might think on a first sight that it will work for int too, because it will only try to call length for strings. But that intuition is wrong: The compiler still checks the string branch, even if that branch is not taken at runtime. And it will find you are trying to call a member function on non-classes if T is an int.
That's why you should separate the code if you need different behavior. But better use overloading instead of specialization, since it's easier to get a clue how things work with it.
template<class T> int foo(T a) {
return a;
}
int foo(std::string const& a) {
return a.length();
}
You have also better separated the code for different paths of behavior. It's not all anymore clued together. Notice that with overloading, the parameters may have different type forms and the compiler will still use the correct version if both match equally well, as is the case here: One can be a reference, while the other can not.
You can check using type_traits (available in Boost and TR1) (e.g. is_same or is_convertible) if you really want to avoid specialization.
You can perform static checks on the type that you have received (look at the boost type traits library), but unless you use specialization (or overloads, as #litb correctly points out) at one point or another, you will not be able to provide different specific implementations depending on the argument type.
Unless you have a particular reason (which you could add to the question) not to use the specialization in the interface just do specialize.
template <> int subtract( std::string const & str );
If you are using C++11 or later, std::is_same does exactly what you want:
template <typename T>
constexpr bool IsFloat() { return std::is_same<T, float>::value; }
template <typename T>
void SomeMethodName() {
if (IsFloat<T>()) {
...
}
}
http://en.cppreference.com/w/cpp/types/is_same