Consider the 2 following overloads
template<typename T>
bool test() {
return true;
}
template<template<typename ...> class T>
bool test() {
return false;
}
The 1st one works for regular classes, while the 2nd one works for templates that are not instantiated.
For instance:
std::cout<<test<int>()<<std::endl; <-- this yields 1
std::cout<<test<std::list>()<<std::endl; <--this yields 0
Now consider the following template function:
template<typename U>
bool templfun(){
struct A{
bool f(){
return test<A>(); // <-- this gives an error
}
};
return test<A>(); // <-- this is ok
}
In GCC it gives an error for ambiguous overload resolution, while Clang compiles.
Interestingly, the second call to test() doesn't produce errors (even in GCC).
Moreover, if I remove the template<typename U> thing on top of templfun, gcc stops complaining.
Is this a bug with GCC or is it illegal code?
GCC is wrong; struct A is a templated entity but clearly not a template (as it does not start with a template keyword), so there is no ambiguity.
To confirm, we can rename the type parameter to see that G++ is attempting to use the template-template overload.
template <typename X>
bool test() {
return true;
}
template <template <typename...> class Y>
bool test() {
return false;
}
template <typename U>
bool templfun() {
struct A {
bool f() {
return test<A>(); // <-- this gives an error
}
};
return test<A>(); // <-- this is ok
}
bool run() {
return templfun<int>();
}
G++ output: (link to godbolt)
<source>:15:27: error: call of overloaded 'test<templfun() [with U = int]::A>()' is ambiguous
15 | return test<A>(); // <-- this gives an error
| ~~~~~~~^~
<source>:2:6: note: candidate: 'bool test() [with X = templfun() [with U = int]::A]'
2 | bool test() {
| ^~~~
<source>:7:6: note: candidate: 'bool test() [with Y = templfun()::A]'
7 | bool test() {
| ^~~~
Clearly "candidate: 'bool test() [with Y = templfun()::A]'" is bogus.
Note that local types were not allowed as template arguments prior to C++11 (see C++03 § 14.3.1.2), so that could explain the complexity of the G++ implementation.
Related
There is a virtual class C.
I would like to ensure that any concrete subclass inheriting from C implements a function "get" (and have a clear compile time error if one does not)
Adding a virtual "get" function to C would not work in this case, as C subclasses could implement get functions of various signatures.
(in the particular case I am working on, pybind11 will be used to creates bindings of the subclasses, and pybind11 is robust of the "get" method of B to have a wide range of signatures)
Checking at compile time if a class has a function can be done with type traits, e.g.
template<class T>
using has_get =
decltype(std::declval<T&>().get(std::declval<int>()));
My question is where in the code should I add a static assert (or smthg else) to check the existence of the "get" function. Ideally, this should be part of C declaration, as things should be easy for new user code inheriting from it. It may also be that a completely different approach would be better, which I'd like to hear.
Not sure what standard you are using but with C++20 you can do something like this using concepts
template<typename T>
concept HasGet = requires (T a)
{
a.get();
};
template<HasGet T>
void foo(T x)
{
x.get();
}
struct Foo
{
int get() {
return 1;
}
};
struct Bar
{
};
int main()
{
foo(Foo{});
foo(Bar{});
}
Error:
<source>: In function 'int main()':
<source>:27:12: error: use of function 'void foo(T) [with T = Bar]' with unsatisfied constraints
27 | foo(Bar{});
| ^
<source>:8:6: note: declared here
8 | void foo(T x)
| ^~~
<source>:8:6: note: constraints not satisfied
<source>: In instantiation of 'void foo(T) [with T = Bar]':
<source>:27:12: required from here
<source>:2:9: required for the satisfaction of 'HasGet<T>' [with T = Bar]
<source>:2:18: in requirements with 'T a' [with T = Bar]
<source>:4:9: note: the required expression 'a.get()' is invalid
4 | a.get();
EDIT:
As C++14 is preferred, if I understand you requirements, this is something you can do in C++14
#include <type_traits>
#include <utility>
using namespace std;
template<typename... Ts>
using void_t = void;
template<typename T, typename = void>
struct has_get
: false_type
{};
template<typename T>
struct has_get<T, void_t<decltype(declval<T>().get())>>
: true_type
{};
template<typename T>
static constexpr auto has_get_v = has_get<T>::value;
struct P
{
};
struct C1 : P
{
int get()
{
return 1;
}
};
struct C2 : P
{
float get()
{
return 1.0F;
}
};
struct C3
{
bool get()
{
return true;
}
};
template<typename T>
enable_if_t<is_base_of<P, decay_t<T>>::value && has_get_v<decay_t<T>>> foo(T x)
{
x.get();
}
int main()
{
foo(C1{});
foo(C2{});
foo(C3{});
}
ERROR:
<source>: In function 'int main()':
<source>:61:11: error: no matching function for call to 'foo(C3)'
61 | foo(C3{});
| ^
<source>:52:77: note: candidate: 'template<class T> std::enable_if_t<(std::is_base_of<P, typename std::decay<_Tp>::type>::value && has_get<typename std::decay<_Tp>::type>::value)> foo(T)'
52 | enable_if_t<is_base_of<P, decay_t<T>>::value && has_get<decay_t<T>>::value> foo(T x)
| ^~~
<source>:52:77: note: template argument deduction/substitution failed:
In file included from <source>:1:
/opt/compiler-explorer/gcc-10.1.0/include/c++/10.1.0/type_traits: In substitution of 'template<bool _Cond, class _Tp> using enable_if_t = typename std::enable_if::type [with bool _Cond = false; _Tp = void]':
<source>:52:77: required by substitution of 'template<class T> std::enable_if_t<(std::is_base_of<P, typename std::decay<_Tp>::type>::value && has_get<typename std::decay<_Tp>::type>::value)> foo(T) [with T = C3]'
<source>:61:11: required from here
/opt/compiler-explorer/gcc-10.1.0/include/c++/10.1.0/type_traits:2554:11: error: no type named 'type' in 'struct std::enable_if<false, void>'
2554 | using enable_if_t = typename enable_if<_Cond, _Tp>::type;
I need to create a template class in C++. I need to make sure that the type for the template parameter will be a class with 1 int field and 1 string field (there can be more fields, but these are mandatory).
For example, in C# I could define an interface with methods or properties, like this:
interface MyInterface {
int GetSomeInteger();
string GetSomeString();
}
and then I could use it in my template class:
class MyClass<T> where T: MyInterface {}
Is there any way to do something like this in C++?
C++20 offers you the closest solution to C#:
#include <concepts>
template <class T>
concept MyInterface = requires(T x)
{
{ x.GetSomeInteger() } -> std::same_as<int>;
};
And then:
template <MyInterface T>
struct MyClass
{
// ...
};
The most common way of doing this in current versions of C++ is a technique known as "duck-typing".
It simply involves just using T as if it implements the interface and let the compiler fail if you use the class with an incompatible type.
template<typename T>
class MyClass<T> {
int foo() {
T val;
return val.GetSomeInteger();
}
};
class Valid {
public:
int GetSomeInteger() {return 0;}
};
class Invalid {
};
int main() {
// works fine
MyClass<Valid> a;
a.foo();
// fails to compile
MyClass<Invalid> b;
b.foo();
}
Mind you, there ARE ways of enforcing this a bit more formally, but the amount of code involved is often not worth the benefit.
C++20 has concepts. Some compilers already support them. For example the following with gcc (trunk) -std=c++2a -fconcepts:
#include <string>
#include <iostream>
#include <concepts>
template<typename T>
concept HasGetIntAndString = requires(T& a) {
{ a.GetSomeInteger() } -> std::same_as<int>;
{ a.GetSomeString() } -> std::same_as<std::string>;
};
template <HasGetIntAndString T>
void bar(const T& t){
std::cout << t.GetSomeInteger() << " " << t.GetSomeString();
}
struct foo {
int GetSomeInteger() const { return 42; }
std::string GetSomeString() const { return "some"; }
};
struct foo_not {
std::string GetSomeInteger() { return "some"; }
int GetSomeString() { return 42; }
};
int main(){
bar( foo{});
bar( foo_not{});
}
results in:
<source>: In function 'int main()':
<source>:28:19: error: use of function 'void bar(const T&) [with T = foo_not]' with unsatisfied constraints
28 | bar( foo_not{});
| ^
<source>:12:6: note: declared here
12 | void bar(const T& t){
| ^~~
<source>:12:6: note: constraints not satisfied
<source>: In instantiation of 'void bar(const T&) [with T = foo_not]':
<source>:28:19: required from here
<source>:6:9: required for the satisfaction of 'HasGetIntAndString<T>' [with T = foo_not]
<source>:6:30: in requirements with 'T& a' [with T = foo_not]
<source>:7:23: note: 'a.GetSomeInteger()' does not satisfy return-type-requirement
7 | { a.GetSomeInteger() } -> std::same_as<int>;
| ~~~~~~~~~~~~~~~~^~
<source>:8:22: note: 'a.GetSomeString()' does not satisfy return-type-requirement
8 | { a.GetSomeString() } -> std::same_as<std::string>;
| ~~~~~~~~~~~~~~~^~
cc1plus: note: set '-fconcepts-diagnostics-depth=' to at least 2 for more detail
Live Demo
Before C++20 you can use SFINAE. However, often it is simpler and more appropriate to not restrict the tempalte parameter more than necessary. If the template does call T::GetSomeInteger() but the type T has no such method, the template will already fail to compile without taking any further measures. SFINAE is mainly to provide nicer error messages.
I want to write a function that returns an instance of a type T but behaves differently depending on how T can be constructed. Say I have structs like these
#include <type_traits>
#include <iostream>
struct A {};
struct B {};
struct C {
C(A a) {
std::cout << "C" << std::endl;
}
};
I want to create Cs by giving them an A. I have a struct like so that uses enable_if to choose one of two functions:
struct E {
template< bool condition = std::is_constructible<C, A>::value,std::enable_if_t<condition,int> = 0>
C get() {
return C{A{}};
}
template< bool condition = std::is_constructible<C, B>::value,std::enable_if_t<condition,bool> = false>
C get() {
return C{B{}};
}
};
This compiles fine with g++82 (and I think also g++9), but clang9 gives me the error
$ clang++ --std=c++17 main.cpp
main.cpp:26:12: error: no matching constructor for initialization of 'C'
return C{B{}};
^~~~~~
main.cpp:6:8: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'B' to 'const C' for 1st argument
struct C {
^
main.cpp:6:8: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'B' to 'C' for 1st argument
struct C {
^
main.cpp:7:3: note: candidate constructor not viable: no known conversion from 'B' to 'A' for 1st argument
C(A a) {
^
1 error generated.
even though the enable_if should hide that function. (I call E e; auto c = e.get();). If I don't hardcode C but instead use a template to pass in C it works in both compilers.
template<typename T>
struct F {
template< bool condition = std::is_constructible<T, A>::value,std::enable_if_t<condition,int> = 0>
T get() {
return T{A{}};
}
template< bool condition = std::is_constructible<T, B>::value,std::enable_if_t<condition,bool> = false>
T get() {
return T{B{}};
}
};
I don't understand why clang apparently typechecks the body of the function even though the function should be disabled by enable_if.
Both compiler are right,
http://eel.is/c++draft/temp.res#8.1
The validity of a template may be checked prior to any instantiation. [ Note: Knowing which names are type names allows the syntax of every template to be checked in this way. — end note ] The program is ill-formed, no diagnostic required, if:
(8.1)
- no valid specialization can be generated for a template or a substatement of a constexpr if statement within a template and the template is not instantiated, or
[..]
(8.4)
- a hypothetical instantiation of a template immediately following its definition would be ill-formed due to a construct that does not depend on a template parameter, or
return C{B{}}; is not template dependent, and wrong. clang is fine by diagnosing the issue.
Since you seem to have access to compilers supporting c++17 you could use if constexpr instead of enable_if to accomplish what you want.
#include <iostream>
#include <type_traits>
struct A {};
struct B {};
struct C {
explicit C(A a) {
std::cout << "C" << std::endl;
}
};
template<typename T>
struct False : std::false_type {};
struct E {
template<typename T = void>
C get() const {
if constexpr (std::is_constructible_v<C, A>) {
return C{A{}};
} else if constexpr (std::is_constructible_v<C, B>) {
return C{B{}};
} else {
static_assert(False<T>::value, "Error");
}
}
};
int main() {
const auto C{E{}.get()};
return 0;
}
The following code compiles perfectly if:
I don't include <iostream> or
I name operator== as alp::operator==.
I suppose there is a problem with <iostream> and operator==, but I don't know what.
I compile the code with gcc 7.3.0, clang++-6.0 and goldbolt. Always the same error.
The problem is that the compiler is trying to cast the parameters of operator== to const_iterator, but why? (I suppose the compiler doesn't see my version of operator==, and looks for other versions).
#include <vector>
#include <iostream> // comment and compile
namespace alp{
template <typename It_base>
struct Iterator {
using const_iterator = Iterator<typename It_base::const_iterator>;
operator const_iterator() { return const_iterator{}; }
};
template <typename It_base>
bool operator==(const Iterator<It_base>& x, const Iterator<It_base>& y)
{ return true;}
}// namespace
struct Func{
int& operator()(int& p) const {return p;}
};
template <typename It, typename View>
struct View_iterator_base{
using return_type = decltype(View{}(*It{}));
using const_iterator =
View_iterator_base<std::vector<int>::const_iterator, Func>;
};
using view_it =
alp::Iterator<View_iterator_base<std::vector<int>::iterator, Func>>;
int main()
{
view_it p{};
view_it z{};
bool x = operator==(z, p); // only compiles if you remove <iostream>
bool y = alp::operator==(z,p); // always compile
}
Error message:
yy.cpp: In instantiation of ‘struct View_iterator_base<__gnu_cxx::__normal_iterator<const int*, std::vector<int> >, Func>’:
yy.cpp:9:73: required from ‘struct alp::Iterator<View_iterator_base<__gnu_cxx::__normal_iterator<const int*, std::vector<int> >, Func> >’
yy.cpp:44:29: required from here
yy.cpp:28:42: error: no match for call to ‘(Func) (const int&)’
using return_type = decltype(View{}(*It{}));
~~~~~~^~~~~~~
yy.cpp:22:10: note: candidate: int& Func::operator()(int&) const <near match>
int& operator()(int& p) const {return p;}
^~~~~~~~
yy.cpp:22:10: note: conversion of argument 1 would be ill-formed:
yy.cpp:28:42: error: binding reference of type ‘int&’ to ‘const int’ discards qualifiers
using return_type = decltype(View{}(*It{}));
~~~~~~^~~~~~~
I've made a more minimal test case here: https://godbolt.org/z/QQonMG .
The relevant details are:
A using type alias does not instantiate a template. So for example:
template<bool b>
struct fail_if_true {
static_assert(!b, "template parameter must be false");
};
using fail_if_used = fail_if_true<true>;
will not cause a compile time error (if fail_if_used isn't used)
ADL also inspects template parameter classes. In this case, std::vector<int>::iterator is __gnu_cxx::__normal_iterator<const int*, std::vector<int> >, Func>, which has a std::vector<int> in it's template. So, operator== will check in the global namespace (always), alp (As alp::Iterator is in alp), __gnu_cxx and std.
Your View_iterator_base::const_iterator is invalid. View_iterator_base::const_interator::result_type is defined as decltype(Func{}(*std::vector<int>::const_iterator{})). std::vector<int>::const_iterator{} will be a vectors const iterator, so *std::vector<int>::const_iterator{} is a const int&. Func::operator() takes an int&, so this means that the expression is invalid. But it won't cause a compile time error if not used, for the reasons stated above. This means that your conversion operator is to an invalid type.
Since you don't define it as explicit, the conversion operator (To an invalid type) will be used to try and match it to the function parameters if they don't already match. Obviously this will finally instantiate the invalid type, so it will throw a compile time error.
My guess is that iostream includes string, which defines std::operator== for strings.
Here's an example without the std namespace: https://godbolt.org/z/-wlAmv
// Avoid including headers for testing without std::
template<class T> struct is_const { static constexpr const bool value = false; } template<class T> struct is_const<const T> { static constexpr const bool value = true; }
namespace with_another_equals {
struct T {};
bool operator==(const T&, const T&) {
return true;
}
}
namespace ns {
template<class T>
struct wrapper {
using invalid_wrapper = wrapper<typename T::invalid>;
operator invalid_wrapper() {}
};
template<class T>
bool operator==(const wrapper<T>&, const wrapper<T>&) {
return true;
}
}
template<class T>
struct with_invalid {
static_assert(!is_const<T>::value, "Invalid if const");
using invalid = with_invalid<const T>;
};
template<class T>
void test() {
using wrapped = ns::wrapper<with_invalid<T>>;
wrapped a;
wrapped b;
bool x = operator==(a, b);
bool y = ns::operator==(a, b);
}
template void test<int*>();
// Will compile if this line is commented out
template void test<with_another_equals::T>();
Note that just declaring operator const_iterator() should instantiate the type. But it doesn't because it is within templates. My guess is that it is optimised out (where it does compile because it's unused) before it can be checked to show that it can't compile (It doesn't even warn with -Wall -pedantic that it doesn't have a return statement in my example).
I'm trying to build up some code that wants to declare a local variable (say of type test, as shown below). Construction of that local variable should use a constructor that takes a special Tag argument if such a constructor exists, or the default constructor otherwise.
What we've been able to come up with is as follows, where we specialize to construct either a void argument or a Tag argument, but compilers don't like that:
#include <iostream>
using std::cout;
struct Tag { };
template <bool z>
struct helper {
using type = void;
};
template <>
struct helper<true> {
using type = Tag;
};
template <bool z>
static typename helper<z>::type get_arg() {
return typename helper<z>::type();
}
struct test {
test(void) { cout << "test(void)\n"; }
test(Tag x) { cout << "test(Tag)\n"; }
test(const test&) = delete;
test(test&&) = delete;
};
template <typename T>
void try_construct() {
// we would be selecting from one of these by template metaprogramming
T a{typename helper<false>::type()};
T b{typename helper<true>::type()};
T c{get_arg<false>()};
T d{get_arg<true>()};
// Then do stuff with the suitably-constructed instance of T
// . . .
}
int main(void) {
try_construct<test>();
return 0;
}
Compiler output:
$ g++ -std=c++11 -c foo.cpp
foo.cpp: In instantiation of 'void try_construct() [with T = test]':
foo.cpp:38:23: required from here
foo.cpp:30:37: error: no matching function for call to 'test::test(<brace-enclosed initializer list>)'
T a{typename helper<false>::type()};
^
foo.cpp:30:37: note: candidates are:
foo.cpp:22:3: note: test::test(Tag)
test(Tag x) { cout << "test(Tag)\n"; }
^
foo.cpp:22:3: note: no known conversion for argument 1 from 'void' to 'Tag'
foo.cpp:21:3: note: test::test()
test(void) { cout << "test(void)\n"; }
^
foo.cpp:21:3: note: candidate expects 0 arguments, 1 provided
foo.cpp:33:23: error: no matching function for call to 'test::test(<brace-enclosed initializer list>)'
T c{get_arg<false>()};
^
foo.cpp:33:23: note: candidates are:
foo.cpp:22:3: note: test::test(Tag)
test(Tag x) { cout << "test(Tag)\n"; }
^
foo.cpp:22:3: note: no known conversion for argument 1 from 'helper<false>::type {aka void}' to 'Tag'
foo.cpp:21:3: note: test::test()
test(void) { cout << "test(void)\n"; }
^
foo.cpp:21:3: note: candidate expects 0 arguments, 1 provided
We know how to test on the presence of the constructor, so I've left that our of the example. If that does end up being relevant in a solution taking a different approach, feel free to go that route.
Our ultimate goal is to require one of the default constructor or the Tag constructor, and neither of the copy or move constructors.
namespace details {
template<class T>
T maybe_tag_construct(std::true_type) {
return T(Tag{});
}
template<class T>
T maybe_tag_construct(std::false_type) {
return T();
}
}
template<class T>
T maybe_tag_construct() {
return details::maybe_tag_construct<T>( std::is_constructible<T, Tag>{} );
}
now auto t =maybe_tag_construct<test>(); constructs test from Tag iff it works.
It also does elided move construction before c++17, and in c++17 no move construction occurs.
In order to pass an instance of void around, you need the "regular void" proposal, which is on track for c++2a last I checked.
I think something along these lines works:
#include <type_traits>
template <typename T, bool B = std::is_constructible<Tag, T>> struct H;
template <typename T>
struct H<T, false> {
T t;
H() : t() {}
};
template <typename T>
struct H<T, true> {
T t;
H() : t(Tag) {}
};
try_construct() {
H<T> h;
h.t;
}