I tried searching for possible implementations of std::ignore, but failed to find a clear answer.
http://mail-archives.apache.org/mod_mbox/stdcxx-dev/200807.mbox/%3C4872AA41.7040005#roguewave.com%3E cites problems with c++ spec and provides and illustrative implementation as
namespace std {
struct _Ignore
{
template <class _Type>
_Ignore& operator= (const _Type& value) { return *this; }
};
const _Ignore ignore = _Ignore ();
} // namespace std
And there are further discussions about the problems. So, how the current implementations looks like? and why?
In GCC it looks like what you posted except that ignore is not const. That overcomes what looks to be the primary objection in the thread you linked.
In Clang the assignment operator is const, and also returns const, and the entire class is itself a template (in addition to the assignment operator being a template). The template instantiation uses unsigned char for whatever reason.
Related
Due to a very very long list of constraints and gotchas... in a special math library that uses libc++ (and in other cases, libstdc++), which I am trying to extend, I am attempting to fully specialize just the division operation because in libc++ it uses functions like scalbn and logb that are not available for the type in question, A in this example. For libstdc++, it doesn't matter since those functions aren't called. Here is a minimal case that triggers the error message I'm running into; see it not work. It is not apparent to me from looking at the -E output what other base template, probably with more parameters, is causing this message, though it also happens with libstdc++. Yes, I realize I should not be defining things in the standard namespace. Yes, I am aware of ADL being able to bring in namespaces as a way to prevent defining things in std, as well as other techniques. That is not what I want to do here. Thank you for any help you can give.
#include <complex>
#include <iostream>
template <class T> struct A{ T a; };
namespace std{
//template <> // if uncommented, warning: extraneous template parameter list in template specialization
template <class T>
inline std::complex<A<T>>
operator/ <A<T>> ( // either way, error: function template partial specialization is not allowed
std::complex<A<T>> const&,
std::complex<A<T>> const&) {
std::cerr<<"full explicit specialization called\n";
return std::complex<A<T>>();
}
}
int main(int,char*[]){
A<double> myA{10};
A<double> myOtherA{5};
std::complex<A<double>> r(std::complex(myA)/std::complex(myOtherA));
std::cerr<<r.real().a<<"\n";
return 0;
}
I've inherited some code that looks like this:
///
/// A specializable function for converting a user-defined object to a string value
///
template <typename value_type>
std::string to_string(const value_type &value)
{
static_assert(!std::is_same<value_type, value_type>::value, "Unspecialized usage of to_string not supported");
return "";
}
///
/// A specializable function for converting a user-defined object from a string to a value
///
template <typename return_type>
return_type from_string(const std::string &source)
{
static_assert(!std::is_same<return_type, return_type>::value, "Unspecialized usage of from_string not supported");
}
!std::is_same<value_type, value_type>::value seems overly verbose.
Should I change these statements to static_assert(false,"...")?
I'm not sure if it was expressed this way to handle some kind of edge case, or if false is indeed equivalent.
Is std::is_same<t,t>::value always true?
The code you posted is ill formed with no diagnostic required.
Replacing it with static_assert(false, ...) makes the compiler notice the fact your code is ill-formed. The code was ill-formed before, the compiler just didn't notice it.
I have two fixes to your problem. One is a hack, but legal. The other is much cleaner, but requires you to write more code.
The first section of this answer is why your code is ill-formed. The next two are solutions.
Why is the code ill-formed?
template <typename value_type>
std::string to_string(const value_type &value)
{
static_assert(!std::is_same<value_type, value_type>::value, "Unspecialized usage of to_string not supported");
return "";
}
The primary template of to_string cannot be instantiated with any type. The C++ standard demands that all templates, including primary templates, must have a valid instantiation (which in standardese is called a valid specialization). (There are other requirements, like at least one such instantiation must have an non-empty pack if there are packs involved, etc).
You may complain that "it compiled and worked", but that is no diagnostic required means. The C++ standard places zero constraints on what the compiler does when it runs into a "ill-formed no diagnostic required" case. It can fail to detect it and blithely compile that "works". It can assume it is impossible, and generate malformed code if it does happen. It can attempt to detect it, fail, and do either of the above. It can attempt to detect it, succeed, and generate an error message. It can detect it, succeed, and generate code that emails thumbnails of every image you looked at in your browser over the last year to all of your contacts.
It is ill-formed, and no diagnostic is required.
I would avoid such code myself.
Now, one might argue that someone could somewhere specialize is_same<T,T> to return false, but that would also make your program ill formed as an illegal specialization of a template from std that violates the requirements on the template as written in the standard.
Replacing !std::is_same<value_type, value_type>::value with false will simply permit your compiler to realize your code is ill formed, and generate an error message. This is, in a sense, a good thing, as ill formed code can break in arbitrary ways in the future.
Hack way to fix it
The stupid way to fix this is to create
template<class T, class U>
struct my_is_same:std::is_same<T,U> {};
which admits the possibility of the specialization loophole. This is still code smell.
Right way to fix it
The right way to write both of these requires a bit of work.
First, to_string and from_string based off tag dispatching instead of template specialization:
namespace utility {
template<class T>struct tag_t {};
template <typename value_type>
std::string to_string(tag_t<value_type>, const value_type &value) = delete;
template <typename value_type>
std::string to_string(const value_type &value) {
return to_string(tag_t<value_type>{}, value);
}
template <typename return_type>
return_type from_string(tag_t<return_type>, const std::string &source) = delete;
template <typename return_type>
return_type from_string(const std::string &source) {
return from_string(tag_t<return_type>{}, source);
}
}
The goal is that the end user simply does a utility::from_string<Bob>(b) or utility::to_string(bob) and it works.
The base ones bounce to tag-dispatches. To customize, you overload the tag-dispatch versions.
To implement the to/from string, in the namespace of Bob write these two functions:
Bob from_string( utility::tag_t<Bob>, const std::string& source );
std::string to_string( utility::tag_t<Bob>, const Bob& source );
notice they are not templates or specializations of templates.
To handle types in std or built-in types, simply define similar overloads in namespace utility.
Now, ADL and tag dispatching take you to the correct to/from string function. No need to change namespaces to define to/from string.
If you call to_string or from_string without a valid tag_t overload, you end up calling the =delete and getting an "overload not found" error.
Test code:
struct Bob {
friend std::string to_string( utility::tag_t<Bob>, Bob const& ) { return "bob"; }
friend Bob from_string( utility::tag_t<Bob>, std::string const&s ) { if (s=="bob") return {}; exit(-1); }
};
int main() {
Bob b = utility::from_string<Bob>("bob");
std::cout << "Bob is " << utility::to_string(b) << "\n";
b = utility::from_string<Bob>( utility::to_string(b) );
std::cout << "Bob is " << utility::to_string(b) << std::endl;
Bob b2 = utility::from_string<Bob>("not bob");
std::cout << "This line never runs\n";
(void)b2;
}
Live example.
(Use of friend is not required, the function just has to be in the same namespace as Bob or within namespace utility).
Consider the following excerpt from the safe bool idiom:
typedef void (Testable::*bool_type)() const;
operator bool_type() const;
Is it possible to declare the conversion function without the typedef? The following does not compile:
operator (void (Testable::*)() const)() const;
Ah, I just remembered the identity meta-function. It is possible to write
operator typename identity<void (Testable::*)() const>::type() const;
with the following definition of identity:
template <typename T>
struct identity
{
typedef T type;
};
You could argue that identity still uses a typedef, but this solution is "good" enough for me.
One case (unrelated to your question) where a typedef is required is when using the
va_arg() macro. Quoting the C99 standard (7.15.1.1):
type* va_arg(va_list ap, type);
...
The parameter type shall be a
type name specified such that the type of a pointer to an object that
has the specified type can be obtained simply by postfixing a * to
type
Answering the "Are there cases where a typedef is absolutely necessary?" from the question title, here is one example of where a typedef is needed:
f(unsigned char()); // compiler error!
typedef unsigned char Byte;
f(Byte()); // fine!
See the results here: http://ideone.com/JPUra
My analysis says that it is not possible without using typedef. The compiler sees ( as the first token and assumes you are overloading () operator, which shouldn't have any arguments (The arguments would come in next set of parenthesis). Putting any set of extra parenthesis wouldn't help either - but would actually confuse the compiler and hence set of more errors.
Most of the STL code is on top of typedefinitions, and we should/must use them!
It seems that the grammar demands using a typedef in your case. A conversion-function-id must be of the form operator conversion-type-id. The conversion-type-id cannot contain parentheses. So you must use typedef when converting to a pointer-to-function type, or to a pointer-to-member-function type.
In C++11, you can do it like this (gcc 4.5.2):
operator decltype((void (Testable::*)() const)(0))() const ;
I'm not saying it's pretty...
A typedef is not a macro your second example is not equivalent to the first. In the first case your typedef is defining a functor then using that type in a cast operator of the functor type. In the second the operator is using bad syntax as there is no operator specified because there is no type. I'm not sure how to write it but there is a way usually.
Typedefs aren't really necessary except for making human readable code in TMP and even then it depends on what kind of human you are.
Since I can't come up with the alternative syntax maybe typedefs are necessary in some cases. I just thought of another one possibly. Say you had a template with specializations which contained a static method with a return type like below:
template <typename T>
struct WhateverHandler
{
typedef T rType;
static rType Whatever() { return rType(); }
};
template <>
struct WhateverHandler<std::string>
{
typedef std::string rType;
static rType Whatever() { return rType(); }
};
I think in this case also you would need the typedef in order to call the static method regardless of specialization as otherwise the method could confuse the compiler because the return types would differ but it wouldn't be a proper overload.
template <typename T>
struct WhateverUser
{
typename WhateverHandler<T>::rType DoWhatever()
{
return WhateverHandler<T>::template Whatever();
}
};
I just ran across this issue, with clang++:
foo.cpp:17:8: error: must use a typedef to declare a conversion to 'void (*(int))()'
and there's a C++11 STL template which covers the identity<T> functionality:
#include <type_traits>
…
struct foo {
void bar( ) const { }
operator std::common_type<void(foo::*)( )const>::type( ) { return &foo::bar; }
};
Learning C++, came upon function templates. The chapter mentioned template specialization.
template <> void foo<int>(int);
void foo( int );
Why specialize when you can use the second? I thought templates were suppose to generalize. What's the point of specializing a function for a specific data type when you can just use a regular function?
Obviously, template specialization exists for a reason. When should it be used? I read Sutter's "Why not Specialize..." article but I need more of a layman's version since I'm just learning this stuff.
The main difference is that in the first case you are providing the compiler with an implementation for the particular type, while in the second you are providing an unrelated non-templated function.
If you always let the compiler infer the types, non-templated functions will be preferred by the compiler over a template, and the compiler will call the free function instead of the template, so providing a non-templated function that matches the arguments will have the same effect of specializations in most cases.
On the other hand, if at any place you provide the template argument (instead of letting the compiler infer), then it will just call the generic template and probably produce unexpected results:
template <typename T> void f(T) {
std::cout << "generic" << std::endl;
}
void f(int) {
std::cout << "f(int)" << std::endl;
}
int main() {
int x = 0;
double d = 0.0;
f(d); // generic
f(x); // f(int)
f<int>(x); // generic !! maybe not what you want
f<int>(d); // generic (same as above)
}
If you had provided an specialization for int of the template, the last two calls would call that specialization and not the generic template.
I personally can see no benefit from specializing a function template. Overloading it by either a different function template or a non-template function is arguably superior because its handling is more intuitive and it's overall more powerful (effectively by overloading the template, you have a partial specialization of the template, even though technically it's called partial ordering).
Herb Sutter has written an article Why not specialize function templates? where he discourages specializing function templates in favour of either overloading them or writing them so that they just forward to a class template's static function and specializing the class template instead.
You can use specialization when you know for a specific class the generic method could be efficient.
template<typename T>
void MySwap(T& lhs, T& rhs)
{
T tmp(lhs);
lhs = rhs;
rhs = tmp;
}
Now for vectors my swap will work, but is not very effecient. But I also know that std::vector implements its own swap() method.
template<>
void MySwap(std::vector<int>& lhs,std::vector<int>& rhs)
{
lhs.swap(rhs);
}
Please don;t compare to std::swap which is a lot more complex and better written. This is just an example to show that a generic version of MySwap() will work but is may not always be efficient. As a result I have shown how it can be made more efficient with a very specific template specialization.
We can also of course use overloading to achieve the same effect.
void MySwap(std::vector<int>& lhs,std::vector<int>& rhs)
{
lhs.swap(rhs);
}
So the question if why use template specialization (if one can use overloading). Why indeed. A non template function will always be chosen over a template function. So template specialization rules are not even invoked (which makes life a lot simpler as those rules are bizarre if you are not a lawyer as well as a computer programmer). So let me thing a second. No can't think of a good reason.
I find it very important. You can use this as you would use a virtual method. There would be no point in virtual methods unless some of them were specialized. I have used it a lot to differentiate between simple types (int,short,float) and objects, object pointers and object references.
An example would be serialize/unserialize methods that would handle objects by calling the objects serialize/unserialize method, while simple types should be written directly to a stream.
One case for template specialization which is not possible with overloading is for template meta-programming. The following is real code from a library that provides some of it services at compile time.
namespace internal{namespace os{
template <class Os> std::ostream& get();
struct stdout{};
struct stderr{};
template <> inline std::ostream& get<stdout>() { return std::cout; }
template <> inline std::ostream& get<stderr>() { return std::cerr; }
}}
// define a specialization for os::get()
#define DEFINE_FILE(ofs_name,filename)\
namespace internal{namespace os{ \
struct ofs_name{ \
std::ofstream ofs; \
ofs_name(){ ofs.open(filename);} \
~ofs_name(){ ofs.close(); delete this; } \
}; \
template <> inline std::ostream& get<ofs_name>(){ return (new ofs_name())->ofs; } \
}} \
using internal::os::ofs_name;
Multiple overloads on the same name do similar things. Specializations do the exact same thing, but on different types. Overloads have the same name, but may be defined in different scopes. A template is declared in only one scope, and the location of a specialization declaration is insignificant (although it must be at the scope of the enclosing namespace).
For example, if you extend std::swap to support your type, you must do so by specialization, because the function is named std::swap, not simply swap, and the functions in <algorithm> would be quite right to specifically call it as ::std::swap( a, b );. Likewise for any name that might be aliased across namespaces: calling a function may get "harder" once you qualify the name.
The scoping issue is confused further by argument-dependent lookup. Often an overload may be found because it is defined in proximity to the type of one of its arguments. (For example, as a static member function.) This is completely different from how the template specialization would be found, which is by simply looking up the template name, and then looking up the explicit specialization once the template has been chosen as the target of the call.
The rules of ADL are the most confusing part of the standard, so I prefer explicit specialization on the priciple of avoiding reliance on it.
According to the standard, a conversion function has a function-id operator conversion-type-id, which would look like, say, operator char(&)[4] I believe. But I cannot figure out where to put the function parameter list. gcc does not accept either of operator char(&())[4] or operator char(&)[4]() or anything I can think of.
Now, gcc seems to accept (&operator char ())[4] but clang does not, and I am inclined to not either, since it does not seem to fit the grammar as I understand it.
I do not want to use a typedef because I want to avoid polluting the namespace with it.
You can use identity
template<typename T>
struct identity { typedef T type; };
struct sample {
operator identity<char[4]>::type &() {
...
}
};
You are correct that function and array declarators won't work in conversion functions. This is also known and discussed in this issue report. However i think that C++0x already provides a solution to what they discuss there
struct sample {
template<typename T>
using id = T;
template<typename T, int N>
operator id<T[N]> &() {
...
}
};
Unlike the identity and typedef approach, this allows T and N to be deduced, i think.
C++ provides no syntax for that. This is one of those cases when you have to use a typedef-name for the type.
In order to avoid polluting the namespace, it is perfectly OK to declare the typedef-name inside the class
struct S {
int a[4];
typedef int A[4];
operator A&() { return a; }
};