I have a small program as follows:
#include <iostream>
template <typename T>
class X{
public:
bool something(){
return true;
}
};
class A: public X<A>{
};
class B: public A, public X<B>{
};
template <typename T>
bool use(T &t)
{
return t.something();
}
int main()
{
B b;
std::cout << "use returned: " << use(b);
}
This will not compile because there is an ambiguity as to which of the two possible versions of something() should be selected:
In instantiation of 'bool use(T&) [with T = B]':
30:43: required from here
22:20: error: request for member 'something' is ambiguous
6:14: note: candidates are: bool X<T>::something() [with T = B]
6:14: note: bool X<T>::something() [with T = A]
In function 'bool use(T&) [with T = B]':
23:1: warning: control reaches end of non-void function [-Wreturn-type]
My question is, how can I resolve this ambiguity if the only place I can edit is the body of use()?
Yes. For example, you can qualify the call to something (godbolt):
template <typename T>
bool use(T &t)
{
return t.A::something();
}
You could add a specialization of the template “use” for the case where T derives from X and then casts to X inside.
template <typename T>
class X{
public:
bool something(){
return true;
}
};
class A: public X<A>{
};
class B: public A, public X<B>{
};
#
# If class derives from X<T> make sure to cast to X<T> before calling something
#
template<typename T>
typename std::enable_if<std::is_base_of<X<T>, T>::value, bool>::type use(T &t)
{
return static_cast<X<T>&>(t).something();
}
#
# This gets run for everything that doesn't derive from X<T>
#
template<typename T>
typename std::enable_if<!std::is_base_of<X<T>, T>::value, bool>::type use(T &t)
{
return t.something();
}
Have to check the syntax though, but this should make sure you get it for your special case while allowing anything with only one “something” call.
Related
Trying to specialize member methods.
Reading this previous question: std::enable_if to conditionally compile a member function
I can quite understand what I am doing wrong.
#include <string>
#include <iostream>
#include <type_traits>
template<typename T>
class Traits
{
};
struct Printer
{
template<typename T>
typename std::enable_if<!std::is_function<decltype(Traits<T>::converter)>::value, void>::type
operator()(T const& object)
{
std::cout << object;
}
template<typename T>
typename std::enable_if<std::is_function<decltype(Traits<T>::converter)>::value, void>::type
operator()(T const& object)
{
std::cout << Traits<T>::converter(object);
}
};
template<>
class Traits<std::string>
{
public:
static std::size_t converter(std::string const& object)
{
return object.size();
}
};
int main()
{
using namespace std::string_literals;
Printer p;
p(5);
p("This is a C-string");
p("This is a C++String"s); // This compiles.
}
Compilation Gives:
> g++ -std=c++1z X.cpp
X.cpp:42:5: error: no matching function for call to object of type 'Printer'
p(5);
^
X.cpp:14:5: note: candidate template ignored: substitution failure [with T = int]: no member named 'converter' in 'Traits<int>'
operator()(T const& object)
^
X.cpp:20:5: note: candidate template ignored: substitution failure [with T = int]: no member named 'converter' in 'Traits<int>'
operator()(T const& object)
^
They both seem to fail because they can't see the method converter. But I am trying to use SFINE and std::enable_if to recognize that this function does not exist and thus only instantiate one of the methods.
The same error is generated for each of the types:
X.cpp:43:5: error: no matching function for call to object of type 'Printer'
p("This is a C-string");
^
X.cpp:14:5: note: candidate template ignored: substitution failure [with T = char [19]]: no member named 'converter' in 'Traits<char [19]>'
operator()(T const& object)
^
X.cpp:20:5: note: candidate template ignored: substitution failure [with T = char [19]]: no member named 'converter' in 'Traits<char [19]>'
operator()(T const& object)
^
Note: It compiles for the std::string version.
You could defer to a private helper function, and use overload resolution to prefer to the positively SFINAE-d overload - and not have a negatively SFINAE-d one:
struct Printer
{
template <class T>
void operator()(T const& object) {
call_impl(object, 0);
}
private:
// selected if Traits<T>::converter exists and is a function
// preferred in this case because int is better than ...
template<typename T>
typename std::enable_if<std::is_function<decltype(Traits<T>::converter)>::value, void>::type
call_impl(T const& object, int)
{
std::cout << Traits<T>::converter(object);
}
// selected if either Traits<T>::converter doesn't exist or isn't a function
template<typename T>
void call_impl(T const& object, ...)
{
std::cout << object;
}
};
One of the nice benefits that we'll get in C++2a with constraining functions is that we can do this without the extra helper:
struct Printer
{
template <class T>
requires std::is_function<decltype(Traits<T>::converter)>::value
void operator()(T const& object)
{
std::cout << Traits<T>::converter(object);
}
template <class T>
void operator()(T const& object)
{
std::cout << object;
}
};
The problem is in how SFINAE works. When substitution fails, the entire function is taken out of the program. So even though your predicate typename std::enable_if<!std::is_function<decltype(Traits<T>::converter)>::value, void>::type is meant to catch the false case, the non-existence of converter will cause the overload to be taken off the table.
The easiest workaround is something like this:
struct Printer
{
template<typename T>
void
impl(T const& object, ...)
{
std::cout << object;
}
template<typename T>
typename std::enable_if<std::is_function<decltype(Traits<T>::converter)>::value, void>::type
impl(T const& object, void*)
{
std::cout << Traits<T>::converter(object);
}
template<typename T>
void
operator()(T const& x)
{
return impl(x, nullptr);
}
};
Basically: You give the compiler something that will always work without using the predicate. The trick here is that nullptr will be matched to void* instead of ..., so it will do what you want.
If you want to get real fun about it, you can make a has_converter function whose return type is true_type or false_type and overload the implementation on that.
struct Printer
{
template<typename T>
std::false_type
has_converter(T const& object, ...);
template<typename T>
typename std::enable_if<std::is_function<decltype(Traits<T>::converter)>::value, std::true_type>::type
has_converter(T const& object, void*);
template<typename T>
void impl(T const& x, std::false_type)
{
std::cout << x;
}
template<typename T>
void impl(T const& x, std::true_type)
{
std::cout << Traits<T>::converter(x);
}
template<typename T>
void
operator()(T const& x)
{
return impl(x, decltype(has_converter(x, nullptr))());
}
};
One can imagine a helper function or templated constexpr bool to make using this property even easier (use the same technique as above).
template <typename T>
constexpr bool has_converter = ???;
How about adding non-function converter to non-specialized trait?
template<typename T>
class Traits
{
public: enum class Dummy{nothing};
public: static Dummy const converter = Dummy::nothing;
};
Run this code online
I have an equivalent to following code:
struct Empty {
static constexpr int id = 0;
};
template <typename Self, typename Base = Empty> struct Compound : public Base
{
int get_id() const
{
return Self::id;
}
};
struct A : Compound<A>
{
static constexpr int id = 0xa;
};
struct B : Compound<B, A>
{
static constexpr int id = 0xb;
};
template <typename T, typename Base> int get_id(const Compound<T, Base> &c)
{
return c.get_id();
}
int test_a()
{
A var;
return get_id(var);
}
int test_b()
{
B var;
return get_id(var);
}
test_b doesn't compile with following error:
error: no matching function for call to 'get_id(B&)'
return get_id(var);
^
note: candidate: template<class T, class Base> int get_id(const Compound<T, Base>&)
template <typename T, typename Base> int get_id(const Compound<T, Base> &c)
^
note: template argument deduction/substitution failed:
note: 'const Compound<T, Base>' is an ambiguous base class of 'B'
return get_id(var);
I understand why that is. B is derived and is convertible to both Compound<B, A> and Compound<A, Empty>
I'm wondering if it is possible to change (within context of C++14) Compound template and get_id() function such that it would return 0xa for A and 0xb for B and would work for arbitrarily long chains of inheritance.
I know that this can be easily solved with virtual function that is overridden in A and B, but I would like to avoid that if possible. Everywhere these types are used they are known and fixed at compile time so there shouldn't be a need to incur run-time overhead.
Just keep it simple:
template <class T>
auto get_id(T const& c) -> decltype(c.get_id())
{
return c.get_id();
}
You don't need c to be some Compound, you really just want it to have a get_id() member function.
It's not clear from your post why need to go the route of Compound in get_id. You can simply use:
template <typename T> int get_id(T const& c)
{
return T::id;
}
We have:
template<typename T>
struct A {
void foo(int a) {
T::foo(a);
}
};
template<typename T>
struct B {
template struct A<T>; // concept check
};
So, I define a concept checker A that checks T by forwarding foo to T::foo.
Now, I want to check whether the argument passed to B satisfies the concept A by explicit instantiation, but the compiler complains that it's the wrong namespace. How can I fix that?
Something like this perhaps:
template<typename T, void(T::*)(int)>
struct A {};
template<typename T>
struct B {
using Check = A<T, &T::foo>;
};
Demo
Or this:
template<typename T>
struct B {
static_assert(
std::is_same<decltype(&T::foo), void(T::*)(int)>::value,
"No T::foo(int) member");
};
So, I found a working example:
#include <tuple>
template<typename A>
struct IA : A {
void foo(int a) {
A::foo(a);
}
void bar(double a) {
A::bar(a);
}
static constexpr auto $ = std::make_tuple(&IA::foo, &IA::bar);
};
template<typename T>
struct B {
// trigger concept/interface check of T "implements" IA
static constexpr auto $ = IA<T>::$;
};
struct Test {
void foo(int a) {}
void bar(int a, int b) {}
};
int main() {
B<Test> b;
b = b;
}
The generation of $ in the structs triggers the compilation. The compiler in the example above correctly complains with:
In instantiation of 'void IA<A>::bar(double) [with A = Test]':
13:57: required from 'constexpr const std::tuple<void (IA<Test>::*)(int), void (IA<Test>::*)(double)> IA<Test>::$'
18:27: recursively required from 'constexpr const std::tuple<void (IA<Test>::*)(int), void (IA<Test>::*)(double)> B<Test>::$'
18:27: required from 'struct B<Test>'
28:13: required from here
10:17: error: no matching function for call to 'IA<Test>::bar(double&)'
10:17: note: candidate is:
24:10: note: void Test::bar(int, int)
24:10: note: candidate expects 2 arguments, 1 provided
If I have a class A
template <typename T>
class A { public: void print() const; };
I can write specific version of my methode print for specific template values my doing
template<> void A<bool>::print() const { printf("A w/ type bool\n"); }
template<> void A<int>::print() const { printf("A w/ type int\n"); }
and the calling the method print will just call the code of the good implementation (of the compiler tell me if I don't have an implementation for a specific template.
Now, if I have multiples types in my class B's template
template <typename T1, typename T2>
class B { public: void print() const; };
and if I try to do the same as before, let's say for T2
template<typename T1> void B<T1,bool>::print() const { printf("B w/ type bool\n"); }
I get an compiler error :
error: invalid use of incomplete type 'class B<T1,bool>'
error: declaration of 'class B<T1, bool>'
What am I doing wrong ?
EDIT
My real life B class contains other methods with I do not want to specify (they work in the general case)
Having a partially specified class decalred makes that those generic methods aren't natively availlable
You can't partial specialize a function/method.
But you can partial specialize the whole class:
template <typename T1, typename T2> class B;
template<typename T1> class B<T1, bool>
{
public:
void print() const { printf("B w/ type bool\n"); }
};
What am I doing wrong?
template<> void A<bool>::print() const { printf("A w/ type bool\n"); }
template<> void A<int>::print() const { printf("A w/ type int\n"); }
These member functions are like normal functions, they are not templates with un-substituted parameters, so you are just providing definitions for the symbols, which will be used when those functions get called. (And like normal functions, if those definitions are in a header and you don't declare them inline you will get multiple definitions errors for them.)
template<typename T1> void B<T1,bool>::print() const { printf("B w/ type bool\n"); }
This is not the same, this is providing a definition for a member function of a class template partial specialization. i.e. it's a template that will be used to generate code for the member of that partial specialization, but you haven't declared any such partial specialization, so you can't define its members.
You can make it compile by defining the partial specialization first:
// primary template
template <typename T1, typename T2>
class B { public: void print() const; };
// partial specialization
template<typename T1>
class B<T1,bool> { public: void print() const; };
template<typename T1> void B<T1,bool>::print() const { printf("B w/ type bool\n"); }
However it is often inconvenient to have to repeat the entire class template definition just to define a partial specialization for one or two members, so it might be worth taking one of the alternative designs shown in other answers.
With templates it's best to decompose each part of the specialisation into its own template function or traits class.
Here's a clean way to do what you want:
template<typename T>
const char* type_name()
{
return "unknown";
};
template<>
const char* type_name<int>()
{
return "int";
}
template<>
const char* type_name<bool>()
{
return "bool";
}
struct foo {};
template<>
const char* type_name<foo>()
{
return "my custom foo";
}
struct bar {};
template <typename T>
class A {
public:
void print() const {
cout << "A w/ type " << type_name<T>() << '\n';
}
};
int main() {
A<bool> ab;
A<int> ai;
A<foo> af;
A<bar> abar;
ab.print();
ai.print();
af.print();
abar.print();
return 0;
}
output:
A w/ type bool
A w/ type int
A w/ type my custom foo
A w/ type unknown
Program ended with exit code: 0
With tag dispatching, you might do:
#include <iostream>
template<typename A, typename B>
class X
{
private:
template <typename U> struct Tag {};
template <typename U>
void print(Tag<U>) const;
void print(Tag<bool>) const { std::cout << "bool\n"; }
void print(Tag<int>) const{ std::cout << "int\n"; }
public:
void print() const { print(Tag<B>()); }
};
int main()
{
X<void, bool>().print();
X<void, int>().print();
}
I have a template function and wish to ensure at compile time that it is not instantiated on a subtype or supertype of a particular class.
How can I cause a C++ compiler error if this is violated?
class base {
};
class derived : public base {
};
class lowest : public derived {
};
template <typename T>
bool isCorrect(const T& obj) {
typedef foo<T> D;
foo<T> *def = foo<T>::find();
return (def && def->getAnswer(object));
}
I want isCorrect to only be available for class derived, but not base or lowest. Note there could be many other lowest classes and a string of base classes to be excluded as well as alternative derived classes that are acceptable.
Is there a way in C++ to limit the template to only apply to the derived classes I explicitly specify?
Type traits, specifically is_base_of.
#include <type_traits>
template <typename T>
bool isCorrect(const T& obj) {
static bool const is_base = std::is_base_of<base, T>::value;
static bool const derives = std::is_base_of<derived, T>::value;
// specify allowed types here
static bool const is_derived = std::is_same<T, derived>::value;
// ---
static_assert((!is_base && !derives) || is_derived, "wrong argument type");
typedef foo<T> D;
foo<T> *def = foo<T>::find();
return (def && def->getAnswer(object));
}
Note that this is C++11 specific, but you can get the same behaviour with Boost.TypeTraits.
Here's one technique that I know of.
First, make another template class policy_enforcer. Declare this class without defining it, and also provide a specialization of it for derived that is also defined:
template<typename T> struct policy_enforcer;
template<> struct policy_enforcer<derived> { };
Then, within the function you wish to lock down, include the expression sizeof(policy_enforcer<T>). Since sizeof on incomplete types is a compilation error, this will prevent the code from compiling.
Updated with live code: using base, using derived, using lowest.
You can use template specialization.
You can implement only the isCorrect only for types that you want to be able to work with.
For the other types you can implement dummy method, returning false for example, or not implement isCorrect at all, in which case it will not compile for other types.
#include <iostream>
using namespace std;
class base {
};
class derived : public base {
};
class lowest : public derived {
};
// using this it will fail if you try to pass anything
// else than `derived`
// template <typename T>
// bool isCorrect(const T& obj);
template <typename T>
bool isCorrect(const T& obj) {
cout << __PRETTY_FUNCTION__ << endl;
return false;
}
template <>
bool isCorrect<derived>(const derived& obj) {
cout << __PRETTY_FUNCTION__ << endl;
return true;
// typedef foo<derived> D;
// foo<derived> *def = foo<derived>::find();
// return (def && def->getAnswer(object));
}
Test:
int main()
{
base b;
derived d;
lowest l;
cout << isCorrect(b) << endl;
cout << isCorrect(d) << endl;
cout << isCorrect(l) << endl;
}
Output:
bool isCorrect(const T&) [with T = base]
0
bool isCorrect(const T&) [with T = derived]
1
bool isCorrect(const T&) [with T = lowest]
0