Why is template disambiguator needed in this case? - c++

I'm trying to understand why I need to use a template disambiguator in some openCL code.
EDIT: Here's a minimal reproducing case:
//test.hpp
#include <iostream>
#include <vector>
#include "cl.hpp"
template <typename T>
class Foo {
public:
std::vector<cl::Platform> platforms;
std::vector<cl::Device> devices;
Foo();
void bar();
};
template<typename T>
Foo<T>::Foo() {
cl::Platform::get(&platforms);
platforms[0].getDevices(CL_DEVICE_TYPE_GPU, &devices);
}
template<typename T>
void Foo<T>::bar() {
// Fails to compile: error: expected expression
//std::cout << devices[0].getInfo<CL_DEVICE_NAME>() << std::endl;
// Works
std::cout << devices[0].template getInfo<CL_DEVICE_NAME>() << std::endl;
// Also works
cl::Device &mydevice = devices[0];
std::cout << mydevice.getInfo<CL_DEVICE_NAME>() << std::endl;
}
and the source file:
//test.cpp
#include "test.hpp"
int main() {
Foo<double> foo = Foo<double>();
foo.bar();
return 0;
}
What is different about the reference that makes a template disambiguator unnecessary? I"m trying to understand where the ambiguity is here. (Also, I know I'm not using the templated variable in my class, this is just a minimal case that reproduced the issue.)

First of all, this is just a typical issue in general in template code. The issue is that because, at the point of parsing the nature of getInfo is unknown (is it a function template or a regular member variable ?) the parser does not know whether to interpret < as less-than or as the start of specifying template parameters.
Thus the rule in ยง14.2 [temp.names]/4, of which the example is:
template<class T> void f(T* p) {
T* p1 = p->alloc<200>(); // ill-formed: < means less than
T* p2 = p->template alloc<200>(); // OK: < starts template argument list
T::adjust<100>(); // ill-formed: < means less than
T::template adjust<100>(); // OK: < starts template argument list
}
Now, in your case this seems a bit silly I fathom, because it's a Device right ? Yes, in your case. But what of:
template <typename T> struct Wrecker { using type = std::vector<Device>; };
template <> struct Wrecker<double> { using type = std::vector<Other>; };
template <typename T>
struct Foo {
using Devices = typename Wrecker<T>::type;
Devices devices;
void bar();
};
So, yes, the rule is not as precise as it could be. It could delve even further into the fray and check whether the actual type can be deduced...
... but do you realize that, as it is, the simple fact of allowing you to elide template in some circumstances (non-dependent situations) already requires one of the worst compiler hacks ever ? The traditional pipeline: tokenization -> parsing -> semantic analysis has to be completely twisted in C++ to allow feedback of semantic analysis during the parsing phase to automatically disambiguate that foo<4>() is a template call.
Personally, my recommendation would have been to mandate template systematically. It would have saved a lot of troubles.

Related

Understanding templates defined inside templates (C++)

According to my understanding, the following two programs should be effectively identical, but the second fails to compile. Note that in this simplified example, the nesting is obviously useless, but it's necessary in the original context.
Version 1: works as expected
#include <iostream>
template<typename Value>
struct Anything {
Value value;
};
using A = const char *;
template<template<typename> class B>
struct Inner {
template<typename C>
using type = B<C>;
};
template<template<typename> class B>
struct OuterBase {
B<A> b;
void
print() { std::cout << "b: " << b.value << std::endl; }
};
using Outer = OuterBase<Inner<Anything>::type>; // this version works
int
main()
{
Outer outer;
outer.b.value = "foo";
outer.print();
return 0;
}
The compiler error in this version is "expected a template, got TypeBox<A>::Inner<Anything>::type".
Version 2: fails with compile error
#include <iostream>
template<typename Value>
struct Anything {
Value value;
};
template<typename A>
struct TypeBox {
template<template<typename> class B>
struct Inner {
template<typename C>
using type = B<C>;
};
template<template<typename> class B>
struct OuterBase {
B<A> b;
void
print() { std::cout << "b: " << b.value << std::endl; }
};
using Outer = OuterBase<Inner<Anything>::type>; // compile error here
};
int
main()
{
using Box = typename TypeBox<const char *>::Outer;
Box box;
box.b.value = "foo";
box.print();
return 0;
}
I would expect the TypeBox struct to be transparent when resolving the types inside, but according to gcc 12.2.1, it isn't. Why not?
The difference in your second example is that a compiler cannot verify at the point of definition of the template that Inner<Anything>::type is really a class template or alias template. The problem is that Inner is a nested class template and you could in theory partially or explicitly specialize Inner for the given template argument later, so that type names e.g. a type.
So compilers tend to require that you place the template keyword before the template's name in such a case to state that it really is a template:
using Outer = OuterBase<Inner<Anything>::template type>;
My understanding is that technically there is nothing in the standard requiring this use of template though, but that this wasn't entirely clear. However, the standard did allow using the template keyword in this position, but will deprecate this allowance with C++23. If I am not mistaken compilers should also allow this without template keyword in the future even for previous standard revisions (as defect report). There wasn't ever really a point in performing this test.
See also CWG issue 1478 and the paper proposing the deprecation P1787R6.

Is it possible to use 'if constexpr' to determine if a template function could be instantiated with a particular type parameter?

Suppose there exists the following code:
class Foo {
public:
void foo() const { std::cout << "foo" << std::endl; }
};
class Bar {
public:
void bar() const { std::cout << "bar" << std::endl; }
};
template <typename T>
void DoFoo(const T& f) {
f.foo();
}
I want to write a function like this:
template <typename T>
void DoFooIfPossible() {
if constexpr (/* DoFoo<T>(T()) would compile */) {
DoFoo(T());
} else {
std::cout << "[not possible]" << std::endl;
}
}
So that:
int main() {
DoFooIfPossible<Foo>();
DoFooIfPossible<Bar>();
}
compiles and prints:
foo
[not possible]
I know that for this particular example I can implement this in the following way by detecting the presence of the member function that DoFoo uses:
template <typename T, typename = void>
struct IsFooPossible : std::false_type {};
template <typename T>
struct IsFooPossible<
T, std::enable_if_t<std::is_member_function_pointer_v<decltype(&T::foo)>>>
: std::true_type {};
template <typename T>
void DoFooIfPossible() {
if constexpr (IsFooPossible<T>::value) {
DoFoo(T());
} else {
std::cout << "[not possible]" << std::endl;
}
}
However, the question I am asking here is: Can I implement this without making any assumptions about the implementation of DoFoo?.
In a real-world scenario, DoFoo may be a library function that I do not own. It may place many different conditions on its template parameter type T, and those conditions may change over time. So replicating those conditions in an enable_if expression in my code is not a viable solution.
I was wondering if it is possible to write my if constexpr expression in a way that directly tests whether DoFoo<T> can be instantiated without having any special knowledge of the implementation of DoFoo, and without modifying DoFoo.
I'm trying to do this in C++17, so if there's something in C++20 that could handle this, that would be interesting to know but wouldn't solve my problem.
(Also note that for the sake of creating a minimal example, I'm assuming T is default-constructable. I don't really care about the T() part of DoFoo(T()) -- I'm trying to determine if DoFoo<T> can be instantiated at all.)
The ultimate solution would be C++20 concepts, because old-school SFINAE methods have their caveats. However there are still compiler bugs that might hunt you down.
You can use a requires clause as an inline concept which can finally evaluate a constexpr bool:
if constexpr(
requires {
/*do your test declaration s*/
}
)//...rest

General function for types and const types without overloading

I know it's generally a bad idea to rely on SFINAE unless absolutely necessary, but I'm curious about how to do the following anyway.
So let's say I have a function that prints a type to the console (class used for partial specialization since it more closely matches my situation):
template <class Ty>
class print
{
public:
print(Ty line)
{
std::cout << line << std::endl;
}
};
Since this is scaled down code, I'm not sure if it would also work with const types, but (because does not in my specific case) let's say the above function does not work with const types. Correct me if I'm wrong, but I believe this would be how you'd accomplish this with partial template specialization?
template <class Ty>
class print <const Ty>
{
public:
print(const Ty line)
{
std::cout << line << std::endl;
}
};
However, is there a way to use the <type_traits> header to do this? I've come across a question that was specific to char* and const char*, but it seems to be different when generalized. Additionally, that question (and answer) is nearly 7 years old.
I've tried the following code (untested) when trying to adapt the answer from the above question to my own situation, but it seems like there should simply be a better way to accomplish this task. In fact, I'm pretty sure my code won't compile (specifically if Ty is already const)
template <class Ty>
struct print_accept_const :
std::enable_if<std::is_same<Ty, Ty>::value || std::is_same<Ty, const Ty>>
{};
template <class Ty, class = print_accept_const<Ty>>
class print
{
print(Ty line)
{
std::cout << line << std::endl;
}
};
Just for reference, I'm using partial template specialization because I'm specializing this print class for std::vector objects, std::set objects, std::unordered_set objects, etc. If there is a way to do this without SFINAE, then I'd be totally open to that.
Edit 1
As asked in a comment, my exact error happens when I try to specialize for std::unordered_set objects.
template <class ValTy>
class print <std::unordered_set<ValTy>>
{
public:
print(std::unordered_set<int> lines) // 'int' instead of 'ValTy' to activate IntelliSense for errors
{
const auto last = --lines.end();
for (auto& line : lines)
{
// IntelliSense, for the line below when 'ValTy' is
// replaced with 'int', says:
//
// no instance of constructor "print<std::unordered_set<ValTy,
// std::hash<ValTy>, std::equal_to<ValTy>, std::allocator<ValTy>>>
// ::print(std::unordered_set<int, std::hash<int>, ...>)" matches
// the argument list. Argument types are (int).
//
print<ValTy> p(line);
}
}
}
Isn't clear what do you exactly want (enable when T is const or isn't const; if you have a function that print value of some types it's necessary wrap it in a template class? Can't you apply SFINAE directly over the function?) anyway... some useful elements...
(1) starting from C++11 there is std::is_const that you can use to check if a type is constant or not
(2) to make an example, a possible way to enable a specialization only for constant types is the following
template <typename T, typename = void>
struct print;
template <typename T>
struct print<T, typename std::enable_if<std::is_const<T>::value>::type>
{
print (T line)
{ std::cout << line << std::endl; }
};
The specialization can be simplified, starting from C++14, using std::enable_if_t
struct print<T, std::enable_if_t<std::is_const<T>::value>>
and, starting from C++17, also using std::is_const_v
struct print<T, std::enable_if_t<std::is_const_v<T>>>
(3) you can enable/disable directly the constructor, but only making is a template one (or SFINAE can't work)
template <typename T>
struct print
{
template <typename U = T,
typename std::enable_if<std::is_const<U>::value, int>::type = 0>
print (U line)
{ std::cout << line << std::endl; }
// possible alternative do-nothing constructor for not const values
template <typename U = T,
typename std::enable_if<! std::is_const<U>::value, int>::type = 0>
print (U)
{ }
};
Observe that, in this case, the SFINAE tests (std::is_same and std::is_const<U>) are (also) over the template parameter of the constructor, U, not over the template parameter of the class, T. Otherwise SFINAE doesn't works.
The first std::enable_if impose that T and U are the same.

C++: Use #if std::is_fundamental<T>::value for conditional compilation in MSVC 2010

In my template I need to have different code parts based on whether the typename is a fundamental type or not.
Compiling this code gives a C4067 in MSVC (unexpected tokens following preprocessor directive - expected a newline):
template <typename T>
void MyClass<T>::foo()
{
// ... some code here
#if std::is_fundamental<T>::value
if(m_buf[j] < m_buf[idx_min])
idx_min = j;
#else
const ASSortable& curr = dynamic_cast<ASSortable&>(m_buf[j]);
const ASSortable& curr_min = dynamic_cast<ASSortable&>(m_buf[idx_min]);
// error checking removed for simplicity
if(curr.before(curr_min))
idx_min = j;
}
#endif
The template is to work with both primitive and my own (derived from ASSortable) data types and the error is thrown from template instantiation code:
template class MyClass<char>;
Trying to modify the precompiler expression to this didn't work either:
#if std::is_fundamental<T>::value == true
and produces the same exact warning.
Any ideas how to make this code warning-free?
Edit Another thing that comes to mind is to convert this into a run-time check and live with the "constant if expression" warning... Is there really no way to do this elegantly in a single function with no specializations and no extra bloat?
Edit #2 So the way I solved this (which was obvious, but somehow escaped me...) was to define a bool ASSortable::operator<(const ASSortable& _o) const {return this->before(_o);}; which does the job and makes the code clean (once again).
No more ifs or #ifdefs or any similar clutter in my code!
Can't believe I even asked that question as it had such an obvious and simple answer :(
The common pattern to solve that issue is moving the function to a base class that is specialized and abusing inheritance to bring it to your scope:
template <typename T, bool is_fundamental>
struct Foo_impl {
void foo() {
}
};
template <typename T>
struct Foo_impl<T,true>
{
void foo() { // is fundamental version
}
};
template <typename T>
class Foo : public Foo_impl<T, std::is_fundamental_type<T>::value> {
// ...
};
Another approach would be to implement those as private functions in your class and dispatch to them internally from foo based on the trait. This is really simple and a cleaner solution, but fails if one of the two versions of the foo_impl will not compile. In that case you can use, as others have suggested a template member function to resolve, but I would still offer the non-templated foo as the public interface, forwarding to a private foo_impl template. The reason is that the template in there is an implementation detail to hack conditional compilation, not part of the interface. You don't want user code calling that member function with different template arguments than the type of your own class. Borrowing from pmr's answer:
template <typename T>
struct Foo
{
template <typename U = T,
typename std::enable_if<
std::is_fundamental<U>::value, int >::type* _ = 0
>
void foo() {
std::cout << "is fundamental" << std::endl;
}
//...
That solution allows user code like:
Foo<int> f;
f.foo<std::string>();
Which will instantiate a function that you don't need nor want, and will execute the logic that you don't want. Even if users don't try to fool your class, the fact that is a template in the interface might be confusing and make users think that it is possible to call it for different types.
Preproccessor is run at an early stage of compilation, before the compiler analyzes the types and knows the meaning of std::is_fundamental<T>::value, hence it cannot work this way.
Instead, use specialization:
template<bool> void f();
template<> void f<true>() {
if(m_buf[j] < m_buf[idx_min])
idx_min = j;
}
template<> void f<false>() {
const ASSortable& curr = dynamic_cast<ASSortable&>(m_buf[j]);
const ASSortable& curr_min = dynamic_cast<ASSortable&>(m_buf[idx_min]);
// error checking removed for simplicity
if(curr.before(curr_min))
idx_min = j;
}
template <typename T>
void MyClass<T>::foo()
{
// ... some code here
f<std::is_fundamental<T>::value>();
}
EDIT: You're likely to need to make f a member function, however it's not directly possible since MyClass<T> is a non-specialized template. You could make f a global which delegates the call to the correct member of MyClass. However, there is another approach.
Using overloading, this becomes:
void MyClass<T>::f(const true_type&) {
if(m_buf[j] < m_buf[idx_min])
idx_min = j;
}
void MyClass<T>::f(const false_type&) {
const ASSortable& curr = dynamic_cast<ASSortable&>(m_buf[j]);
const ASSortable& curr_min = dynamic_cast<ASSortable&>(m_buf[idx_min]);
// error checking removed for simplicity
if(curr.before(curr_min))
idx_min = j;
}
template <typename T>
void MyClass<T>::foo()
{
// ... some code here
f(std::is_fundamental<T>::type());
}
You are mixing up states of compilation. The preprocessor is run before the actual compiler and has no knowledge of types or templates. It just performs (very) sophisticated text substitution.
There is nothing such as static if1 in current C++, so you have to resort to a different method to enable conditional compilation. For functions I would prefer enable_if.
#include <type_traits>
#include <iostream>
template <typename T>
struct Foo
{
template <typename U = T,
typename std::enable_if<
std::is_fundamental<U>::value, int >::type = 0
>
void foo() {
std::cout << "is fundamental" << std::endl;
}
template <typename U = T,
typename std::enable_if<
!(std::is_fundamental<U>::value), int >::type = 0
>
void foo() {
std::cout << "is not fundamental" << std::endl;
}
};
struct x {};
int main()
{
Foo<int> f; f.foo();
Foo<x> f2; f2.foo();
return 0;
}
1 References:
Video: Static if presented by Alexandrescu in Going Native.
n3322: Walter E. Brown's proposal for static if
n3329: Sutter, Bright and Alexandrescu's proposal for static if
It's pretty much what it says, you can't use :: in preprocessor directives. Actually, the only thing you can use after #if is a constant-expression that is defined before the compile-time. You can find some info here
std::is_fundamental<T>::value == true cannot be used at pre-processing time. I guess you would have to use some SFINAE trick with std::enable_if:
template <typename T>
typename std::enable_if<std::is_fundamental<T>::value, void>::type
MyClass<T>::foo()
{
// ... some code here
if(m_buf[j] < m_buf[idx_min])
idx_min = j;
}
template <typename T>
typename std::enable_if<!std::is_fundamental<T>::value, void>::type
MyClass<T>::foo()
{
// ... some code here
const ASSortable& curr = dynamic_cast<ASSortable&>(m_buf[j]);
const ASSortable& curr_min = dynamic_cast<ASSortable&>(m_buf[idx_min]);
// error checking removed for simplicity
if(curr.before(curr_min))
idx_min = j;
}

Can I exclude some methods from manual template instantiation?

We have complex template classes that have some methods which will not work with certain policies or types. Therefore, when we detect those types (at compile time, using type-traits) we fire a static assertion with a nice message.
Now we do a lot of manual template instantiation as well. Partly it is so that the methods are forced to compiler to syntax check the methods. It also reduces compile time for the library user. The problem is that the static assertions are always fired and consequently we cannot manually instantiate the template class in question.
Is there a workaround for this?
EDIT: To make it clearer, here is an example (the explicit instantiation in this case will fail on someFunc1():
// header
template <typename T>
class someClass
{
void someFunc() {}
void someFunc1() { static_assert(false, assertion_failed); }
};
// source
template someClass<int>; // Explicit instantiation
EDIT2: Here is another example. This time you can compile it to see what I mean. First compile right away. The code should compile. Then Uncomment [2] and the static assertion should fire. Now comment out [2] and Uncomment [1]. The static assertion will fire because you are explicitly instantiating the template. I want to avoid removing explicit instantiation because of the benefits that come with it (see above for benefits).
namespace Loki
{
template<int> struct CompileTimeError;
template<> struct CompileTimeError<true> {};
}
#define LOKI_STATIC_CHECK(expr, msg) \
{ Loki::CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; }
template <typename T>
class foo
{
public:
void func() {}
void func1() { LOKI_STATIC_CHECK(sizeof(T) == 4, Assertion_error); }
};
template foo<int>;
//template foo<double>; // [1]
int main()
{
foo<int> a;
a.func1();
foo<double> b;
//b.func1(); //[2]
return 0;
}
You can't have both: you can't have a static assertion to prevent instantiation and explicitly instantiate the type! This is an obvious contradiction. What you can have, however, is conditionally included functionality even though it is somewhat a pain in the neck: If a certain member function is not supposed to be supported for certain types, you can move this function into a base class which conditionally has it. This way you wouldn't use a static assertion but just remove the member function. I realize that this introduces interesting other problems, e.g. with respect to the location of member variables, but I think in the context you are describing this is the best you can get.
Here is a quick example of how this could look like:
template <typename T, bool = std::numeric_limits<T>::is_integer> struct foo_base;
template <typename T> struct foo_base<T, false> { /* intentionally left blank */ };
template <typename T> struct foo_base<T, true> { void foo() { /*...*/ } };
template <typename T>
struct Foo: foo_base<T> { /* .... */ };
template struct Foo<int>; // will have foo()
template struct Foo<double>; // will not have foo()
Alright, so if you're forcing the instantiation of all methods using explicit instantiation, you can't get away with any compile time tricks to prevent instantiation of the offending methods, such as enable_if. It'd be easy enough to move the error to runtime, but that's undesirable.
I think the best you can do is move the error to link time, which will statically ensure that the program does not contain a code path that could potentially call the prohibited function, but the error messages won't be very helpful to anyone that doesn't know about the restriction you're imposing. Anyway, the solution is to declare a specialization of the prohibited member functions but not define them:
template<typename T>
struct Foo {
void bar() {
std::cout << "bar\n";
}
void baz() {
std:: cout << "baz\n";
}
};
template<> void Foo<int>::baz(); // use of Foo<int>::baz() will resolve to this specialization, and linking will fail
template struct Foo<int>;
template struct Foo<char>;
int main() {
Foo<int> f;
f.bar();
// f.baz(); // uncommenting this line results in an ugly link time error
Foo<char> b;
b.bar();
b.baz(); // works with Foo<char>
}
The static asserts no longer help give nice error messages when a mistake is made in client code, but you might want to leave them in because they'll fire if you forget to provide a specialization.
enable_if is a flexible mechanism for precise template methods targeting, may be what you are after. Example:
#include <string>
#include <iostream>
#include <boost/utility.hpp>
#include <boost/type_traits.hpp>
#include <boost/static_assert.hpp>
template <class T> class mywrapper
{
T _value;
template <class V>
typename boost::enable_if<boost::is_scalar<V>, void>::type printval_(V const& value)
{
BOOST_STATIC_ASSERT(boost::is_scalar<V>::value);
std::cout << "scalar: " << value << std::endl;
}
template <class V>
typename boost::enable_if<boost::is_compound<V>, void>::type printval_(V const& value)
{
BOOST_STATIC_ASSERT(boost::is_compound<V>::value);
std::cout << "compound: " << value << std::endl;
}
public:
mywrapper(T const& value):_value(value) { }
void printval() { printval_(_value); }
};
template class mywrapper<int>;
template class mywrapper<std::string>;
int main()
{
mywrapper<int> ival(333);
mywrapper<std::string> sval("test");
ival.printval();
sval.printval();
return 0;
}
I did not get an opportunity to test enable_if as suggested by bobah but I did come up with a solution that does not require boost and that satisfies my original requirement to a good extent (I say good and not full, will explain at the end)
The solution is to put a dummy template on the code that will fail if compiled under some selected types and is fine under others. So:
struct dummyStruct {};
#define DUMMY_TEMP typename dummy
#define DUMMY_PARAM dummyStruct
namespace Loki
{
template<int> struct CompileTimeError;
template<> struct CompileTimeError<true> {};
}
#define LOKI_STATIC_CHECK(expr, msg) \
{ Loki::CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; }
template <typename T>
class foo
{
public:
void func() {}
template <typename T_Dummy>
void func1() { LOKI_STATIC_CHECK(sizeof(T) == 4, Assertion_error); }
};
template foo<int>;
template foo<double>; // [1]
int main()
{
foo<int> a;
a.func1<DUMMY_PARAM>();
foo<double> b;
//b.func1<DUMMY_PARAM>(); //[2] - this is a static error
return 0;
}
In all of my template code, these kind of functions (i.e. the ones that have static asserts OR work on some types and may fail on others by using type traits [in which case there is a selection of several different functions for different types]) are hidden from the client. So in my implementation, adding the extra dummy parameter is an OK compromise.
As a bonus, it lets me know that this function is designed to be used by only certain types. Furthermore, my original problem of explicit instantiation is solved by this simple technique.