I have three template arguments to a function and am having troubles with (I think) the compiler deducing which template argument is which.
The template function is:
#include <structures/partition.h>
#include <vector>
namespace cliques
{
template <typename P, typename T, typename QF>
P find_optimal_partition_louvain(cliques::Graph<T> &my_graph,
QF quality_function)
{
P dummy;
}
}
And when I try to call it with
cliques::find_optimal_partition_louvain<cliques::DisjointSetForest>(my_new_graph, cliques::find_linearised_stability(current_markov_time));
Where template argument P should correspond to cliques::DisjointSetForest, and the normal function arguments are a templated class and a function object.
This fails with
error: no matching function for call to
find_optimal_partition_louvain(cliques::Graph<lemon::ListGraph>&,
cliques::find_linearised_stability)
However if I use a builtin type such as an int or a float for the P parameter everything compiles fine.
e.g.
cliques::find_optimal_partition_louvain<int>(my_new_graph, cliques::find_linearised_stability(current_markov_time));
So my question is what am I doing wrong here, how can I use a better inform the compiler which parameter is which, or am I completely off track?
I hate to answer my own question but problem was that cliques::DisjointSubsetForest is actually a templated class so
cliques::find_optimal_partition_louvain<cliques::DisjointSetForest<int> >(my_new_graph, cliques::find_linearised_stability(current_markov_time));
works
"error: no matching function for call to ‘find_optimal_partition_louvain(cliques::Graph&, cliques::find_linearised_stability)"
It would seem that your compiler thinks that cliques::Graph is not a template.
I have tried to reproduce the error on a simple example, but I failed to do so (on gcc).
It looks as though the compiler does figure out that find_optimal_partition_louvain is a function template. I suggest trying the following:
cliques::template find_optimal_partition_louvain<cliques::DisjointSetForest>(my_new_graph, cliques::find_linearised_stability(current_markov_time));
Otherwise, you might want to verify if the following simple example compiles fine on your compiler (because it should!):
#include <iostream>
template <class G>
struct Bar { };
namespace Foo {
template <class A, class B, class C>
A some_function(Bar<B>&, C aFunc) {
aFunc();
return A();
};
};
struct HWPrinter {
HWPrinter() { std::cout << "Hello World!" << std::endl; };
};
struct IntPrinter {
int value;
IntPrinter(int aValue) : value(aValue) { };
void operator() () { std::cout << "The integer is: " << value << std::endl; };
};
int main() {
Bar<HWPrinter> ab;
Foo::some_function<HWPrinter>(ab,IntPrinter(42));
return 0;
};
Related
I am using function SFINAE heavily in a project and am not sure if there are any differences between the following two approaches (other than style):
#include <cstdlib>
#include <type_traits>
#include <iostream>
template <class T, class = std::enable_if_t<std::is_same_v<T, int>>>
void foo()
{
std::cout << "method 1" << std::endl;
}
template <class T, std::enable_if_t<std::is_same_v<T, double>>* = 0>
void foo()
{
std::cout << "method 2" << std::endl;
}
int main()
{
foo<int>();
foo<double>();
std::cout << "Done...";
std::getchar();
return EXIT_SUCCESS;
}
The program output is as expected:
method 1
method 2
Done...
I have seen method 2 used more often in stackoverflow, but I prefer method 1.
Are there any circumstances when these two approaches differ?
I have seen method 2 used more often in stackoverflow, but I prefer method 1.
Suggestion: prefer method 2.
Both methods work with single functions. The problem arises when you have more than a function, with the same signature, and you want enable only one function of the set.
Suppose that you want enable foo(), version 1, when bar<T>() (pretend it's a constexpr function) is true, and foo(), version 2, when bar<T>() is false.
With
template <typename T, typename = std::enable_if_t<true == bar<T>()>>
void foo () // version 1
{ }
template <typename T, typename = std::enable_if_t<false == bar<T>()>>
void foo () // version 2
{ }
you get a compilation error because you have an ambiguity: two foo() functions with the same signature (a default template parameter doesn't change the signature).
But the following solution
template <typename T, std::enable_if_t<true == bar<T>(), bool> = true>
void foo () // version 1
{ }
template <typename T, std::enable_if_t<false == bar<T>(), bool> = true>
void foo () // version 2
{ }
works, because SFINAE modify the signature of the functions.
Unrelated observation: there is also a third method: enable/disable the return type (except for class/struct constructors, obviously)
template <typename T>
std::enable_if_t<true == bar<T>()> foo () // version 1
{ }
template <typename T>
std::enable_if_t<false == bar<T>()> foo () // version 2
{ }
As method 2, method 3 is compatible with selection of alternative functions with same signature.
In addition to max66's answer, another reason to prefer method 2 is that with method 1, you can (accidentally) pass an explicit type parameter as the second template argument and defeat the SFINAE mechanism completely. This could happen as a typo, copy/paste error, or as an oversight in a larger template mechanism.
#include <cstdlib>
#include <type_traits>
#include <iostream>
// NOTE: foo should only accept T=int
template <class T, class = std::enable_if_t<std::is_same_v<T, int>>>
void foo(){
std::cout << "method 1" << std::endl;
}
int main(){
// works fine
foo<int>();
// ERROR: subsitution failure, as expected
// foo<double>();
// Oops! also works, even though T != int :(
foo<double, double>();
return 0;
}
Live demo here
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 have a template where a function is overloaded so it can handle both an std::string parameter and the type of parameter that the template gets instantiated with. This works fine except when the template is being instantiated with std::string, since this results in two member functions with the same prototype. Thus, I have chosen to specialize that function for this particular case. However, it seems like the compiler (g++ 4.8.1 with flag -std=c++0x) never gets to the point where the specialization is actually overriding the primary template and it complains about the ambiguous overload the before it seems to realize that it should use the specialization. Is there a way to get around this?
#include <iostream>
template<class T>
struct A {
std::string foo(std::string s) { return "ptemplate: foo_string"; }
std::string foo(T e) { return "ptemplate: foo_T"; }
};
template<> //Error!
std::string A<std::string>::foo(std::string s) { return "stemplate: foo_string"; }
int main() {
A<int> a; //Ok!
std::cout << a.foo(10) << std::endl;
std::cout << a.foo("10") << std::endl;
//A<std::string> b; //Error!
//std::cout << a.foo("10") << std::endl;
return 0;
}
This results in compile errors, even if I don't instantiate at all with std::string (it seems that the compiler instantiates with std::string as soon as it sees the specialization and that it, before it actually processes the specialization, complains about the ambiguous overload which the specialization, in turn, will "disambiguate").
Compiler output:
p.cpp: In instantiation of 'struct A<std::basic_string<char> >':
p.cpp:10:27: required from here
p.cpp:6:14: error: 'std::string A<T>::foo(T) [with T = std::basic_string<char>; std::string = std::basic_string<char>]' cannot be overloaded
std::string foo(T e) { return "ptemplate: foo_T"; }
^
p.cpp:5:14: error: with 'std::string A<T>::foo(std::string) [with T = std::basic_string<char>; std::string = std::basic_string<char>]'
std::string foo(std::string s) { return "ptemplate: foo_string"; }
^
I would like it to just skip through the implementation of foo() in the primary template and use the specialization without considering the primary template foo(). Could it be done somehow, maybe with non-type template parameters, or do I have to make a fully specialized class template for std::string with all the code duplication it implies (I prefer not to use inheritance here)... Other suggestions?
When you specilize your member function you still get the double ambiguous declaration. Waht you need is to specialize the struct template:
template<>
struct A<std::string> {
std::string foo(std::string s) { return "ptemplate: foo_string"; }
};
If there are many members to the A struct maybe you can refactor:
template<typename T>
struct Afoo
{
std::string foo(T s) { ... }
std::string foo(std::string s) { ... }
};
template<>
struct Afoo<std::string>
{
std::string foo(std::string s) { ... }
};
template<typename T>
struct A : Afoo<T>
{
//a lot of code
};
I'm going to answer this myself since I've been diving deep into this subject today and I think these solutions are nice. All other posts up to this point have been contributive and have had attractive details with potential in other situations. However, I preferred to do it with these things in mind:
Avoid the use of more than one class template
Avoid too complicated specializations as far as possible
Avoid using inheritance and refactor into base and derived classes
Avoid the use of extra wrappers
Please feel free to comment before I accept it as my answer.
Another good and inspiring post on the subject focusing on the use of member function overloading rather than specializations can be found at explicit specialization of template class member function
Solution 1
template<class T>
struct A {
template<class V = T> std::string foo(T) { return "foo_T"; }
std::string foo(std::string) { return "foo_std::string"; }
std::string foo(const char *) { return "foo_const char *"; }
};
template<> template<>
std::string A<std::string>::foo(std::string s) { return foo(s); }
I think this is a dense and understandable solution allowing all class instantiations to use foo(std::string) and foo(const char *) (for passing a string as an rvalue). The use of a dummy template parameter effectively stops class instantiations with std::string from resulting in ambiguous overloads at the same time as the actual template argument hinders uncontrolled function instantiations with unpredictable function arguments. The only problem might come from a class instantiation with std::string that might use the template instead of the regular member function if explicitly called with foo<std::string>(std::string) in which way I would want the class to use the regular foo(std::string) instead of the function template for other instantiations. This is resolved by using a single template specialization.
Solution 2
template<class T>
struct A {
template<class V> std::string foo(V s) { return foo_private(s); }
private:
template<class V = T> std::string foo_private(T) { return "foo_T"; }
std::string foo_private(const char *) { return "foo_const char *"; }
std::string foo_private(std::string) { return "foo_std::string"; }
};
This version allows us to skip the specialization to the benefit of a second template in the class declaration.
Both versions used with:
int main() {
A<int> a;
std::cout << a.foo(10) << std::endl;
std::cout << a.foo("10") << std::endl;
A<std::string> b;
std::cout << b.foo<std::string>("10") << std::endl;
std::cout << b.foo("10") << std::endl;
return 0;
}
... outputted:
foo_T
foo_const char *
foo_const char *
foo_std::string
The error is saying that you ended up creating two method with the same signature.
That is because the struct has been templated with a std::string as parameter.
You should made the function as a templated function, using its own template parameters 'K' not related to the structure template parameter 'T'. Then you can achieve template specialization for the function only.
I admit that the solution I offer below, is a hacky solution indeed, but it does accomplish what you're trying to do and it's kinda funny. Please consider it thoroughly before you use this ;-)
I work around the issue by creating a new type, called FakeType, which can be constructed from your template-type T. The second overload of foo is now for FakeType<T> instead of T, so even when T == string there will be two different overloads:
template <typename T>
struct FakeType
{
T t;
FakeType(T const &t_): t(t_) {}
operator T() { return t; }
};
template <typename T>
struct A
{
string foo(string s) { return "ptemplate: foo_string"; }
string foo(FakeType<T> e) { return "ptemplate: foo_T"; }
};
For the case that T != string:
A<int>().foo("string"); // will call foo(string s)
A<int>().foo(1); // will call foo(FakeType<int> e)
In the latter case, the int will be promoted to a FakeType<int>, which can be used as a regular int through the conversion operator.
For the case that T == string:
A<string>().foo("string"); // will still call foo(string s)
Because the compiler will always prefer an overload for which no promotion is necessary.
PS. This approach assumes that foo is going to get its arguments either by value, or by const-reference. It will break as soon as you try to pass by reference (this can be fixed).
I would like to extract the type of the member a member pointer points to.
template<someType myClass::*member>
void demo(myClass& instance, void* ptr) {
instance.*member = *reinterpret_cast<someType*>(ptr); // can the someType in this line be deduced from member?
}
I tried using decltype as suggested in the comments, however I have issues with this:
instance.*member= static_cast<decltype(instance.*member)>((*buffer)[offset]);
buffer is a std::shared_ptr<std::vector<uint8_t>>,
someType is uint32_t
I get the following error message:
error: invalid static_cast from type
‘__gnu_cxx::__alloc_traits >::value_type
{aka unsigned char}’ to type ‘uint32_t& {aka unsigned int&}’
As far as I understand decltype(instance.*member) with member defined as uint32_t instance::*member yields a reference uint32_t& rather than uint32_t. I tried to pass instance by value and the error remains. I am aware of std::remove_reference however, I do not understand how the reference gets to be there in the first place.
A further improvement would be if I could extract the someType without a class instance. However I have no clue how to achieve this, while I can get the class without a pointer by having the std lib like:
template <T*>
struct removePointer {
typedef T type;
}
I have no Idea how to write this in a form where I can get the someType part of the class, without knowing the class first. I could write something like the following however I would still have to pass the class naem and typename explicitly, is there a way to extract these automatically? Furthermore the following doe not compile in the first place (http://ideone.com/8VlKO4):
#include
using namespace std;
template <class C,typename T, T C::*v>
struct getPointerType {
typedef T type;
};
class Test {
int value;
};
int main() {
int Test::*member=nullptr;
cout << typeid(getPointerType<Test, int, decltype(member)>::type) << std::endl;
return 0;
}
Frankly, it's a bit hard to understand what you're trying to achieve, so I will focus on the updated part.
Clearly, you can not pass types (derived from decltype) as value arguments to the template. Moreover, you can not pass non constexpr values as template arguments (so you can not just stick the member variable into the template argument and expect it to compile).
However, you can rely on compiler to be able to deduce a correct function to call on non costexpr variable:
template <class C, typename T>
T getPointerType(T C::*v);
class Test {
int value;
};
int main() {
int Test::*member=nullptr;
cout << typeid(decltype(member)).name() << std::endl;
cout << typeid(decltype(getPointerType(member))).name() << std::endl;
return 0;
}
The above will print:
M4Testi //int Test::*
i //int
It is, of course, possible to "abuse" the template substitution even more:
template <typename M>
struct getPointerType {
template <typename C, typename T>
static T get_type(T C::*v);
typedef decltype(get_type(static_cast<M>(nullptr))) type;
};
class Test {
int value;
};
int main() {
int Test::*member=nullptr;
cout << typeid(getPointerType<decltype(member)>::type).name() << std::endl;
return 0;
}
The output will be the expected "i".
Here's a solution using template specialization technique :
#include <type_traits>
template <class T>
struct member_type_helper;
template <class C, class T>
struct member_type_helper<T C::*> { using type = T; };
template <class T>
struct member_type
: member_type_helper<typename std::remove_cvref<T>::type> {};
// Helper type
template <class T>
using member_type_t = member_type<T>::type;
Example of usage :
#include <iostream>
struct Foo { int i; };
int main()
{
auto ptr1 = &Foo::i;
auto const& ptr2 = &Foo::i;
volatile auto const ptr3 = &Foo::i; // let's go crazy
// prints true true true
std::cout << std::boolalpha
<< std::same_as<int, member_type_t<decltype(ptr1)>> << '\n'
<< std::same_as<int, member_type_t<decltype(ptr2)>> << '\n'
<< std::same_as<int, member_type_t<decltype(ptr3)>> << '\n';
}
I guess std::remove_cvref might be an overkill for most usage, but hey, it's free. If your compiler isn't >C++20 compliant, you could use std::remove_cv instead (> C++11).
I am trying to achieve type checking of template class parameters by disallowing implicit type conversions such as string->bool thereby throwing compile error.
The specific scenario is a simple one as follows:
#include <iostream>
#include <string>
using namespace std;
template <class T>
class myPair {
T a, b;
public:
myPair(T first, T second ) {
a = first;
b = second;
}
void test();
};
typedef myPair<bool> boolParm;
template<class T>
void myPair<T>::test() {
if(a == true) {
cout << "a is true" << endl;
} else {
cout << "a is false" << endl;
}
if(b == true) {
cout << "b is true" << endl;
} else {
cout << "b is false" << endl;
}
}
int main() {
boolParm myObj(false, "false");
myObj.test();
return 0;
}
The output of the above scenario is undesirable since the user may inadvertently pass 2 different types: bool and string and receive the first one as false (correct since passed as bool) but the second one will be true (incorrect since implicit type conversion from string to bool).
I wish to restrict the user code in main() to throw compile errors and disallowing string/int parameters to pass in the constructor. It should only allow bool.
I tried by using an overloaded constructor myPair(bool first, string second) but it didn't match since I guess the implicit type conversion from string->bool happens before the constructor is called.
Is there any solution using template specializations in this scenario?
Any help is highly appreciated
Thanks
One workaround is to add a templated factory function to create the myPair.
template <typename T>
myPair<T> makeParam(T a, T b) {
return myPair<T>(a, b);
}
That will fail to compile with ambiguous template parameter T if the types don't match. You can extend this with template specializations explicitly forbidding certain types for T. Your main function will then look something like:
int main() {
boolParm myObj = makeParam(false, "false");
myObj.test();
return 0;
}
Alternatively change the constructor:
template <typename U, typename V>
myPair(U a, V b);
And specialize as necessary
An example of such specialization:
template <class T>
class myPair {
T a, b;
public:
template <typename U, typename V> // generic version
myPair(U first, V second)
{
// intentionally fail to compile
static_assert(false, "don't support generic types");
}
template <> // template specialization
myPair(T first, T second)
{
// explicitly require exactly type T
a = first;
b = second;
}
};
It is indeed weird behavior at first glance; but as far as I can say, you can't prohibit that - not for primitive types like bool, anyway.
The implicit conversion of parameters happen before you get a say on it, and it seems there is an implicit primitive type conversion from char const * to bool.
See also e.g. this other question: Why does a quoted string match bool method signature before a std::string?