Reputation: 11047
For example, I have overloaded functions, f()
, they are defined as
struct Test {
int i = 1;
Test(double d) : i (d){}
};
struct MyClass {
int f(double d) {
cout << "parent\n";
return d + 3 ; }
};
struct Child : public MyClass {
using MyClass::f; // if we comment out this line, the output will be different
double f(Test t) {
cout << "child\n";
return t.i * 9;
}
};
int main() {
Child c;
std:: cout << c.f(1.0) << std::endl;
}
The function f
in Child class overloaded the function in parent. How can we generate diagnostic information during compiling time, such that we know which function is chosen by the compiler for c.f(1.0)
?
Note that if I remove the line using MyClass:f;
, the output will be different but there are no error for compiling.
Update:
Based on @P.W 's answer, there are two ways to modify the existing class to use template instantiation to output the static assertion,
template <typename T>
struct ConditionalFalse {
static constexpr bool value = false;
};
struct Test {
int i = 1;
Test(double d) : i (d){}
};
struct MyClass {
template<typename T>
int f(double i) {
static_assert(ConditionalFalse<T>::value, "Parent");
return i + 3 ; }
};
struct Child : public MyClass {
using MyClass::f;
template<typename T>
double f(Test t) {
static_assert(ConditionalFalse<T>::value, "Child");
return t.i * 9;
}
};
template<typename T>
struct MyClassT {
int f(double i) {
static_assert(ConditionalFalse<T>::value, "ParentT");
return i + 3 ; }
};
template<typename T>
struct ChildT : public MyClassT<T> {
using MyClassT<T>::f;
double f(Test t) {
static_assert(ConditionalFalse<T>::value, "ChildT");
return t.i * 9;
}
};
int main() {
Child c;
std:: cout << c.f<int>(1.0) << std::endl;
ChildT<int> ct;
std:: cout << ct.f(1.0) << std::endl;
}
I am still wondering if this is possible without
modifying the class or the member function to be a template?
Upvotes: 0
Views: 58
Reputation: 26800
A simple static_assert(false_condition, "...")
would fail at compile time always. So you need something that happens at compile-time and is still dependent on something else. You can do this if your MyClass
and Child
were templates.
You will also need a dependent expression, and so you can use a helper struct to get something that will be type-dependent.
Now your code will look like this:
#include<iostream>
template <typename T>
struct ConditionalFalse { static constexpr bool value = false; };
struct Test {
int i = 1;
Test(double d) : i (d){}
};
template <typename T>
struct MyClass {
int f(double d) {
static_assert(ConditionalFalse<T>::value, "The Parent function is called\n");
return d + 3 ; }
};
template <typename T>
struct Child : public MyClass<T> {
using MyClass<T>::f; // if we comment out this line, the output will be different
double f(Test t) {
static_assert(ConditionalFalse<T>::value, "The Child function is called\n");
return t.i * 9;
}
};
int main() {
Child<int> c; //The template parameter doesn't matter
std::cout << c.f(1.0) << std::endl;
}
Depending on whether using MyClass<T>::f;
is commented or not you will get different assertions.
If it is not commented, you will get:
error: static assertion failed: The Parent function is called
static_assert(ConditionalFalse<T>::value, "The Parent function is called\n");
^~~~~~~~~~~~~~~~~~~
If it is commented, you will get:
<source>:22:19: error: static assertion failed: The Child function is called
static_assert(ConditionalFalse<T>::value, "The Child function is called\n");
^~~~~~~~~~~~~~~~~~~
You can see it live here.
Upvotes: 2