0

(Noob alert here---I'm not really a C++ programmer, just finding myself needing to reimplement some C++ code in Java.)

I am attempting to understand the following function from OpenFST as part of an effort to enable reading of OpenFST binary files in JOpenFST:

template <class T,
typename std::enable_if<std::is_class<T>::value, T>::type* = nullptr>
inline std::istream &ReadType(std::istream &strm, T *t) {
        return t->Read(strm);
}

I can't determine what in this template declaration guarantees the existence of Read on t. I realize my understanding of enable_if and is_class are fuzzy, but I don't see what there could provide such a method.

Perhaps it comes from the broader context? Something that declares a Read for all class types??? Here are the imports in util.h where that function resides:

#include <iostream>
#include <iterator>
#include <list>
#include <map>
#include <set>
#include <sstream>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

#include <fst/compat.h>
#include <fst/types.h>
#include <fst/log.h>
#include <fstream>

#include <fst/flags.h>
#include <unordered_map>

Thank you for your patience with a confused Java dev.

Josh Hansen
  • 917
  • 1
  • 9
  • 20

1 Answers1

1

I can't determine what in this template declaration guarantees the existence of Read on t.

Nothing guarantees the existence.

That is: If the template is instantiated with a T which doesn't have a Read member function, then the compiler will complain that a non-existent function was called.

From another perspective, the fact that the template is ill-formed unless T::Read exists (and is invocable with given argument) guarantees that T in any well formed instantiation of the template will have such member.

eerorika
  • 232,697
  • 12
  • 197
  • 326
  • So the body of the function and not just the template and signature statically constrain the types that can be passed in? My only comparison with a language I'm familiar with is Rust's traits---there every method call in the body must be justified by the bounds placed on the types in the declaration. – Josh Hansen Jan 19 '19 at 22:17
  • 2
    @JoshHansen in a way, C++ doesn't have a direct way of constraining template arguments - although [SFINAE](https://en.cppreference.com/w/cpp/language/sfinae) rules make it possible to constrain the arguments indirectly (which is what `enable_if` does). – eerorika Jan 19 '19 at 22:25
  • Ah, I didn't realize that. So a template class is duck-typed in a way? But the checking is at comple-time, not runtime. My followup question then would be: how does `i32` (the type this function is being called on in the code I'm concerned with) end up having a `Read` function? Can intrinsic types be augmented with arbitrary methods somehow? Here is the calling code, btw: http://www.openfst.org/doxygen/fst/html/fst_8cc_source.html#l00062 – Josh Hansen Jan 19 '19 at 23:11
  • @JoshHansen `std::enable_if::value, T>::type` prevents this template from being instantiated with non class types. Presumably there is an overload which would be resolved to in such case. – eerorika Jan 19 '19 at 23:14
  • Ah, yes, it's there: `template ::value, T>::type* = nullptr> inline std::istream &ReadType(std::istream &strm, T *t) { return strm.read(reinterpret_cast(t), sizeof(T)); \ }` – Josh Hansen Jan 20 '19 at 00:16