I have some code.
#include <iostream>
template<typename T>
struct Test
{
Test(bool v):flg(v) { }
void func() { }
typedef void (Test::*unspecified)();
operator unspecified() const
{
return flg ? &Test::func : 0;
}
bool flg;
};
template<typename T>
std::ostream& operator << (std::ostream&, typename Test<T>::unspecified);
int main()
{
Test<int> t(true);
std::cout << t << std::endl;
}
Output is
1
It works fine, but i want to get undefined reference. If Test is not template class i get undefined reference. So, why compiler not use operator << for function type and do standart conversion from pointer to class-member to bool?
In typename Test<T>::unspecified, T is in a non-deducible context, since it appears to the left of a ::. Thus your function template is never even considered, and the conversion to unspecified is used as the sole viable overload.
The short answer is simply that "templates don't work like that". Let me know if you want a longer answer.
Related
This question already has answers here:
Officially, what is typename for?
(8 answers)
Closed 3 years ago.
I was studying about SFINAE in modern C++ which I see the following code:
#include <iostream>
struct Bar
{
typedef double it;
};
template <typename T>
typename T::it Foo(const T& arg_f) {
std::cout << "Foo<T>" << std::endl;
return 0;
}
int Foo(int i) { std::cout << "foo(int)" << std::endl; return 0; }
int main(int argc, const char* argv[])
{
Foo(Bar());
Foo(0);
return 0;
}
Why in this code, the developer used typename T::it?
How that typename is related to structure of Bar? because it variable is just defined in bar struct but it used outside of struct for function declaration.
What is SFINAE at all?
The keyword typename is used here because you are accessing a type member of a template type argument.
It is completely unrelated except for the fact that if T is Bar then it should expose a it type member to gain access to the overload.
Substitution Failure Is Not An Error is a template meta programming pattern that relies on "removing" overloads that could not compile
In the template function you put here, the developer indirectly specifies Foo is just a function to work with Bar structure (or its derivated instances). So if you instantiated it like Foo(Bar()), the template function deduced by compiler like the following:
Bar::it Foo(const Bar& arg_f) {
std::cout << "Foo<T>" << std::endl;
return 0;
}
But if we pass an integer value rather Bar object to the function, it will be instantiated like the following codes:
int::it Foo(const int& arg_f) {
std::cout << "Foo<T>" << std::endl;
return 0;
}
Which has a wrong implementation and as a result, the compiler will fail because int class has not it member.
However, if you want to handle this issue, you should overload foo function for int values like the following:
int Foo(int arg_f)
{
std::cout << "Foo<int>" << std::endl;
return arg_f;
}
Or you can use enable_if_t for enabling a template function for a specialized data type like floating-point or ...:
template <typename T>
typename std::enable_if_t<std::is_floating_point<T>::value, T> Foo(T t)
{
std::cout << "Foo<floating point>" << std::endl;
return t;
}
Also, I should clarify type name just make a difference between a value and a type. when you use it, the compiler treats that object as a type, not a value because of that, the developer uses it to make compiler aware it is a type, not a value.
Also, as #Vivick said, Substitution Failure Is Not An Error is a template metaprogramming pattern that relies on "removing" overloads that could not compile. However, Wikipedia has a good reference for SFINAE: https://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error
I want to test whether a class is streamable to ostream& by seeing whether an overload for operator<< is provided. Based on these posts, I tried to write another version using C++11. This is my attempt:
#include <iostream>
#include <type_traits>
namespace TEST{
class NotDefined{};
template<typename T>
NotDefined& operator << (::std::ostream&, const T&);
template <typename T>
struct StreamInsertionExists {
static std::ostream &s;
static T const &t;
enum { value = std::is_same<decltype(s << t), NotDefined>() };
};
}
struct A{
int val;
friend ::std::ostream& operator<<(::std::ostream&, const A&);
};
::std::ostream& operator<<(::std::ostream& os, const A& a)
{
os << a.val;
return os;
}
struct B{};
int main() {
std::cout << TEST::StreamInsertionExists<A>::value << std::endl;
std::cout << TEST::StreamInsertionExists<B>::value << std::endl;
}
But this fails to compile:
test_oper.cpp:40:57: error: reference to overloaded function could not be resolved; did you mean to call it?
std::cout << TEST::StreamInsertionExists<A>::value << std::endl;
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ostream:1020:1: note:
possible target for call
endl(basic_ostream<_CharT, _Traits>& __os)
test_oper.cpp:30:17: note: candidate function not viable: no known conversion from 'TEST::NotDefined' to '::std::ostream &'
(aka 'basic_ostream<char> &') for 1st argument
::std::ostream& operator<<(::std::ostream& os, const A& a)
test_oper.cpp:15:15: note: candidate template ignored: couldn't infer template argument 'T'
NotDefined& operator << (::std::ostream&, const T&);
However, if I replace the line
enum { value = std::is_same<decltype(s << t), NotDefined>() };
with
static const bool value = std::is_same<decltype(s << t), NotDefined>();
then everything compiles.
Why is there such a difference between the enum and the bool?
value is an enum of anonymous name in StreamInsertionExists<T>. When you try to do:
std::cout << StreamInsertionExists<T>::value;
The compiler is doing overload lookup on operator<<(std::ostream&, StreamInsertionExists<T>::E). In the typical case, it'd do integral promotion on the enum and stream it as int. However, you additionally defined this operator:
template<typename T>
NotDefined& operator << (std::ostream&, const T&);
That is a better match for the enum than the int version (Exact Match vs integral promotion), so it is preferred. Yes, it's a function template, but non-templates are only preferred if the conversion sequences match - and in this case they don't.
Thus, this line:
std::cout << TEST::StreamInsertionExists<A>::value << std::endl;
which is:
operator<<(operator<<(std::cout, TEST::StreamInsertionExists<A>::value), std::endl);
And the inner most operator<< call will use your NotDefined& template. Thus, the next step would be to find an appropriate function call for:
operator<<(NotDefined&, std::endl);
and there is no such overload for operator<< hence the error.
If you change value to be bool, there is no such problem because there is an operator<< that takes bool exactly: #6. That said, even with bool, your trait is still incorrect as it always returns false. Your NotDefined version actually returns a reference, so you'd have to check against that. And also, NotDefined& means not defined, so you'd have to flip the sign:
static const bool value = !std::is_same<decltype(s << t), NotDefined&>();
However, this is particularly error prone. Now cout << B{}; instead of failing to compile would instead give you a linker error, and cout << B{} << endl; gives you the same confusing overload error involving endl instead of simply statying that you can't stream a B.
You should prefer to just do:
template <typename...>
using void_t = void;
template <typename T, typename = void>
struct stream_insertion_exists : std::false_type { };
template <typename T>
struct stream_insertion_exists<T, void_t<
decltype(std::declval<std::ostream&>() << std::declval<T>())
> > : std::true_type { };
I am providing a library that supports a function bar(). What it does when you pass in a scalar value (like a double, int, whatever) is different from what happens if you pass in something that is not a scalar value (in all expected cases, a user-defined type). So I wrote code like this:
#include <iostream>
class Foo
{
public:
template <class T> void bar(T const &rhs) { std::cout << "T" << std::endl; }
void bar(double rhs) { std::cout << "double" << std::endl; }
};
int main()
{
Foo foo;
foo.bar(4);
}
The problem with this is on the second line of main(). The result of this code is output of "T". The compiler prefers the template over the call to bar(double), and I am assuming this is because the parameter is an int, which it would rather cast to int const& (since a const& can reference an r-value).
My question is "is there a way I can support every scalar value without explicitly calling them out?" I really don't want to call out every possible type, because... well... there's a lot of them. I would have to cover everything from char to long long, include every combination of volatile and unsigned, and so forth.
I know that just changing the 4 to a 4.0 works, but this is for the public interface to a library, and requiring the user to type 4.0 instead of 4 is just dirty.
Yes, with traits:
#include <type_traits>
#include <iostream>
class Foo
{
public:
template <class T>
typename std::enable_if<!std::is_scalar<T>::value, void>::type bar(T const & rhs)
{
std::cout << "T" << std::endl;
}
void bar(double rhs)
{
std::cout << "double" << std::endl;
}
};
There are six basic categories of types: scalars, functions, arrays, classes, unions and references. And void. Each of them have a corresponding trait. See here for more details.
How do I avoid implicit casting on non-constructing functions?
I have a function that takes an integer as a parameter,
but that function will also take characters, bools, and longs.
I believe it does this by implicitly casting them.
How can I avoid this so that the function only accepts parameters of a matching type, and will refuse to compile otherwise?
There is a keyword "explicit" but it does not work on non-constructing functions. :\
what do I do?
The following program compiles, although I'd like it not to:
#include <cstdlib>
//the function signature requires an int
void function(int i);
int main(){
int i{5};
function(i); //<- this is acceptable
char c{'a'};
function(c); //<- I would NOT like this to compile
return EXIT_SUCCESS;
}
void function(int i){return;}
*please be sure to point out any misuse of terminology and assumptions
Define function template which matches all other types:
void function(int); // this will be selected for int only
template <class T>
void function(T) = delete; // C++11
This is because non-template functions with direct matching are always considered first. Then the function template with direct match are considered - so never function<int> will be used. But for anything else, like char, function<char> will be used - and this gives your compilation errrors:
void function(int) {}
template <class T>
void function(T) = delete; // C++11
int main() {
function(1);
function(char(1)); // line 12
}
ERRORS:
prog.cpp: In function 'int main()':
prog.cpp:4:6: error: deleted function 'void function(T) [with T = char]'
prog.cpp:12:20: error: used here
This is C++03 way:
// because this ugly code will give you compilation error for all other types
class DeleteOverload
{
private:
DeleteOverload(void*);
};
template <class T>
void function(T a, DeleteOverload = 0);
void function(int a)
{}
You can't directly, because a char automatically gets promoted to int.
You can resort to a trick though: create a function that takes a char as parameter and don't implement it. It will compile, but you'll get a linker error:
void function(int i)
{
}
void function(char i);
//or, in C++11
void function(char i) = delete;
Calling the function with a char parameter will break the build.
See http://ideone.com/2SRdM
Terminology: non-construcing functions? Do you mean a function that is not a constructor?
8 years later (PRE-C++20, see edit):
The most modern solution, if you don't mind template functions -which you may mind-, is to use a templated function with std::enable_if and std::is_same.
Namely:
// Where we want to only take int
template <class T, std::enable_if_t<std::is_same_v<T,int>,bool> = false>
void func(T x) {
}
EDIT (c++20)
I've recently switched to c++20 and I believe that there is a better way. If your team or you don't use c++20, or are not familiar with the new concepts library, do not use this. This is much nicer and the intended method as outlines in the new c++20 standard, and by the writers of the new feature (read a papers written by Bjarne Stroustrup here.
template <class T>
requires std::same_as(T,int)
void func(T x) {
//...
}
Small Edit (different pattern for concepts)
The following is a much better way, because it explains your reason, to have an explicit int. If you are doing this frequently, and would like a good pattern, I would do the following:
template <class T>
concept explicit_int = std::same_as<T,int>;
template <explicit_int T>
void func(T x) {
}
Small edit 2 (the last I promise)
Also a way to accomplish this possibility:
template <class T>
concept explicit_int = std::same_as<T,int>;
void func(explicit_int auto x) {
}
Here's a general solution that causes an error at compile time if function is called with anything but an int
template <typename T>
struct is_int { static const bool value = false; };
template <>
struct is_int<int> { static const bool value = true; };
template <typename T>
void function(T i) {
static_assert(is_int<T>::value, "argument is not int");
return;
}
int main() {
int i = 5;
char c = 'a';
function(i);
//function(c);
return 0;
}
It works by allowing any type for the argument to function but using is_int as a type-level predicate. The generic implementation of is_int has a false value but the explicit specialization for the int type has value true so that the static assert guarantees that the argument has exactly type int otherwise there is a compile error.
Maybe you can use a struct to make the second function private:
#include <cstdlib>
struct NoCast {
static void function(int i);
private:
static void function(char c);
};
int main(){
int i(5);
NoCast::function(i); //<- this is acceptable
char c('a');
NoCast::function(c); //<- Error
return EXIT_SUCCESS;
}
void NoCast::function(int i){return;}
This won't compile:
prog.cpp: In function ‘int main()’:
prog.cpp:7: error: ‘static void NoCast::function(char)’ is private
prog.cpp:16: error: within this context
For C++14 (and I believe C++11), you can disable copy constructors by overloading rvalue-references as well:
Example:
Say you have a base Binding<C> class, where C is either the base Constraint class, or an inherited class. Say you are storing Binding<C> by value in a vector, and you pass a reference to the binding and you wish to ensure that you do not cause an implicit copy.
You may do so by deleting func(Binding<C>&& x) (per PiotrNycz's example) for rvalue-reference specific cases.
Snippet:
template<typename T>
void overload_info(const T& x) {
cout << "overload: " << "const " << name_trait<T>::name() << "&" << endl;
}
template<typename T>
void overload_info(T&& x) {
cout << "overload: " << name_trait<T>::name() << "&&" << endl;
}
template<typename T>
void disable_implicit_copy(T&& x) = delete;
template<typename T>
void disable_implicit_copy(const T& x) {
cout << "[valid] ";
overload_info<T>(x);
}
...
int main() {
Constraint c;
LinearConstraint lc(1);
Binding<Constraint> bc(&c, {});
Binding<LinearConstraint> blc(&lc, {});
CALL(overload_info<Binding<Constraint>>(bc));
CALL(overload_info<Binding<LinearConstraint>>(blc));
CALL(overload_info<Binding<Constraint>>(blc));
CALL(disable_implicit_copy<Binding<Constraint>>(bc));
// // Causes desired error
// CALL(disable_implicit_copy<Binding<Constraint>>(blc));
}
Output:
>>> overload_info(bc)
overload: T&&
>>> overload_info<Binding<Constraint>>(bc)
overload: const Binding<Constraint>&
>>> overload_info<Binding<LinearConstraint>>(blc)
overload: const Binding<LinearConstraint>&
>>> overload_info<Binding<Constraint>>(blc)
implicit copy: Binding<LinearConstraint> -> Binding<Constraint>
overload: Binding<Constraint>&&
>>> disable_implicit_copy<Binding<Constraint>>(bc)
[valid] overload: const Binding<Constraint>&
Error (with clang-3.9 in bazel, when offending line is uncommented):
cpp_quick/prevent_implicit_conversion.cc:116:8: error: call to deleted function 'disable_implicit_copy'
CALL(disable_implicit_copy<Binding<Constraint>>(blc));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Full Source Code: prevent_implicit_conversion.cc
Well, I was going to answer this with the code below, but even though it works with Visual C++, in the sense of producing the desired compilation error, MinGW g++ 4.7.1 accepts it, and invokes the rvalue reference constructor!
I think it must be a compiler bug, but I could be wrong, so – anyone?
Anyway, here's the code, which may turn out to be a standard-compliant solution (or, it may turn out that that's a thinko on my part!):
#include <iostream>
#include <utility> // std::is_same, std::enable_if
using namespace std;
template< class Type >
struct Boxed
{
Type value;
template< class Arg >
Boxed(
Arg const& v,
typename enable_if< is_same< Type, Arg >::value, Arg >::type* = 0
)
: value( v )
{
wcout << "Generic!" << endl;
}
Boxed( Type&& v ): value( move( v ) )
{
wcout << "Rvalue!" << endl;
}
};
void function( Boxed< int > v ) {}
int main()
{
int i = 5;
function( i ); //<- this is acceptable
char c = 'a';
function( c ); //<- I would NOT like this to compile
}
I first tried PiotrNycz's approach (for C++03, which I'm forced to use for a project), then I tried to find a more general approach and came up with this ForcedType<T> template class.
template <typename T>
struct ForcedType {
ForcedType(T v): m_v(v) {}
operator T&() { return m_v; }
operator const T&() const { return m_v; }
private:
template <typename T2>
ForcedType(T2);
T m_v;
};
template <typename T>
struct ForcedType<const T&> {
ForcedType(const T& v): m_v(v) {}
operator const T&() const { return m_v; }
private:
template <typename T2>
ForcedType(const T2&);
const T& m_v;
};
template <typename T>
struct ForcedType<T&> {
ForcedType(T& v): m_v(v) {}
operator T&() { return m_v; }
operator const T&() const { return m_v; }
private:
template <typename T2>
ForcedType(T2&);
T& m_v;
};
If I'm not mistaken, those three specializations should cover all common use cases. I'm not sure if a specialization for rvalue-reference (on C++11 onwards) is actually needed or the by-value one suffices.
One would use it like this, in case of a function with 3 parameters whose 3rd parameter doesn't allow implicit conversions:
function(ParamType1 param1, ParamType2 param2, ForcedType<ParamType3> param3);
int x = fromString("test") :could not deduce template argument for 'ValueType'
int x = fromString<int>("test") : works fine as expected
So why does the compiler struggle here? I see it with all kinds of real template functions, not just this silly example. It must be a feature of the language, but what?
You can't deduce based on the return type. You can, however, implement a workaround with similar syntax, using the overloaded cast operator:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
class FromString{
private:
string m_data;
public:
FromString(const char*data) : m_data(data) {}
template<typename T>
operator T(){
T t;
stringstream ss(m_data);
ss >> t;
return t;
}
};
template<> FromString::operator bool(){
return (m_data!="false"); //stupid example
}
int main(){
int ans = FromString("42");
bool t = FromString("true");
bool f = FromString("false");
cout << ans << " " << t << " " << f << endl;
return 0;
}
Output:
42 1 0
C++ doesn't do type inference on the return value. I.e., the fact that it is being assigned to an int isn't used in template parameter deduction.
(Removed edit, since someone else presented the overloaded cast solution already.)
Besides the bad choice for an example (probably makes sense to have int x = to<int>("1235") rather than toString), the problem is that the return type does not participate in overload resolution or type inference[1]. The reason for this is that the expression can be used in many places where the type of the return cannot be deduced:
// assuming template <typename T> T to( std::string ):
//
f( to("123") ); // where there are two overloads f(int), f(double)
int x = 1.5 * to("123"); // T == int? T == double?
to("123"); // now what? returned object can be ignored!
So the decision is that the return type will not take part in overload resolution or type deduction.
[1] There is a single exception to this rule, which is the evaluation of a function pointer with more than one overload, where the overload must be selected by either the destination pointer or an explicit cast, but this is just the one exception and is not used in any other context:
void f();
void f(int);
void g( void (*)() );
void g( void (*)(int) );
void (*p1)() = &f; // overload selected based on destination type
void (*p2)(int) = &f;
g( (void (*)(int))&f ); // overload selected based on explicit cast
It looks like your template has the return type templated which cannot be automatically deduced which is why you need to add it in here.
The return type of a function is dependent on overload resolution, not the other way around.
There is a trick that works though: operator= usually exists only for equal LHS/RHS argument types, except when an explicit operator= is defined (whether as standalone or as a member does not matter).
Thus, overload resolution will find operator=(int &, int), and see if the return value from your function is convertible to int. If you return a temporary that has an operator int, this is an acceptable resolution (even if the operator int is in the generic form of a template<typename T> operator T).
Thus:
template<typename T, typename U>
U convert_impl(T const &t);
template<typename T>
struct convert_result {
convert_result(T const &t) : t(t) { }
template<typename U> operator U(void) const { return convert_impl<U>(t); }
T const &t;
};
template<typename T>
convert_result<T> convert(T const &t) { return t; }